fixed merge conflicts
This commit is contained in:
commit
33a5e01264
|
@ -85,6 +85,22 @@ jobs:
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
make test_unit
|
make test_unit
|
||||||
|
|
||||||
|
test_cli:
|
||||||
|
<<: *defaults
|
||||||
|
parallelism: 1
|
||||||
|
steps:
|
||||||
|
- attach_workspace:
|
||||||
|
at: /tmp/workspace
|
||||||
|
- restore_cache:
|
||||||
|
key: v1-pkg-cache
|
||||||
|
- restore_cache:
|
||||||
|
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run:
|
||||||
|
name: Test cli
|
||||||
|
command: |
|
||||||
|
export PATH="$GOBIN:$PATH"
|
||||||
|
make test_cli
|
||||||
|
|
||||||
test_cover:
|
test_cover:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
parallelism: 4
|
parallelism: 4
|
||||||
|
@ -138,6 +154,9 @@ workflows:
|
||||||
- lint:
|
- lint:
|
||||||
requires:
|
requires:
|
||||||
- setup_dependencies
|
- setup_dependencies
|
||||||
|
- test_cli:
|
||||||
|
requires:
|
||||||
|
- setup_dependencies
|
||||||
- test_unit:
|
- test_unit:
|
||||||
requires:
|
requires:
|
||||||
- setup_dependencies
|
- setup_dependencies
|
||||||
|
|
|
@ -4,3 +4,5 @@
|
||||||
* [ ] Updated all code comments where relevant
|
* [ ] Updated all code comments where relevant
|
||||||
* [ ] Wrote tests
|
* [ ] Wrote tests
|
||||||
* [ ] Updated CHANGELOG.md
|
* [ ] 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)
|
||||||
|
|
|
@ -19,8 +19,11 @@ baseapp/data/*
|
||||||
coverage.txt
|
coverage.txt
|
||||||
profile.out
|
profile.out
|
||||||
|
|
||||||
### Vagrant ###
|
# Vagrant
|
||||||
.vagrant/
|
.vagrant/
|
||||||
*.box
|
*.box
|
||||||
*.log
|
*.log
|
||||||
vagrant
|
vagrant
|
||||||
|
|
||||||
|
# Graphviz
|
||||||
|
dependency-graph.png
|
58
CHANGELOG.md
58
CHANGELOG.md
|
@ -1,30 +1,18 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 0.18.1
|
|
||||||
|
|
||||||
BREAKING CHANGES
|
BREAKING CHANGES
|
||||||
|
|
||||||
* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes:
|
FEATURES
|
||||||
* 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
|
IMPROVEMENTS
|
||||||
|
* export command now writes current validator set for Tendermint
|
||||||
|
|
||||||
* auto-sequencing transactions correctly
|
FIXES
|
||||||
* query sequence via account store
|
* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs
|
||||||
* fixed duplicate pub_key in stake.Validator
|
|
||||||
|
|
||||||
## 0.18.0
|
## 0.18.0
|
||||||
|
|
||||||
_TBD_
|
_2018-06-05_
|
||||||
|
|
||||||
BREAKING CHANGES
|
BREAKING CHANGES
|
||||||
|
|
||||||
|
@ -43,6 +31,20 @@ BREAKING CHANGES
|
||||||
* Introduction of Unbonding fields, lowlevel logic throughout (not fully implemented with queue)
|
* Introduction of Unbonding fields, lowlevel logic throughout (not fully implemented with queue)
|
||||||
* Introduction of PoolShares type within validators,
|
* Introduction of PoolShares type within validators,
|
||||||
replaces three rational fields (BondedShares, UnbondingShares, UnbondedShares
|
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
|
FEATURES
|
||||||
|
|
||||||
|
@ -56,14 +58,25 @@ FEATURES
|
||||||
* [stake] Creation of a validator/delegation generics in `/types`
|
* [stake] Creation of a validator/delegation generics in `/types`
|
||||||
* [stake] Helper Description of the store in x/stake/store.md
|
* [stake] Helper Description of the store in x/stake/store.md
|
||||||
* [stake] removed use of caches in the stake keeper
|
* [stake] removed use of caches in the stake keeper
|
||||||
|
* [stake] Added REST API
|
||||||
* [Makefile] Added terraform/ansible playbooks to easily create remote testnets on Digital Ocean
|
* [Makefile] Added terraform/ansible playbooks to easily create remote testnets on Digital Ocean
|
||||||
|
|
||||||
|
|
||||||
BUG FIXES
|
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
|
* [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!
|
^ 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
|
* [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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 0.17.2
|
## 0.17.2
|
||||||
|
|
||||||
|
@ -87,7 +100,7 @@ FEATURES
|
||||||
* [gaiacli] Support queries for candidates, delegator-bonds
|
* [gaiacli] Support queries for candidates, delegator-bonds
|
||||||
* [gaiad] Added `gaiad export` command to export current state to JSON
|
* [gaiad] Added `gaiad export` command to export current state to JSON
|
||||||
* [x/bank] Tx tags with sender/recipient for indexing & later retrieval
|
* [x/bank] Tx tags with sender/recipient for indexing & later retrieval
|
||||||
* [x/stake] Tx tags with delegator/candidate for delegation & unbonding, and candidate info for declare candidate / edit candidacy
|
* [x/stake] Tx tags with delegator/candidate for delegation & unbonding, and candidate info for declare candidate / edit validator
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
|
|
||||||
|
@ -103,6 +116,7 @@ BUG FIXES
|
||||||
|
|
||||||
* Auto-sequencing now works correctly
|
* Auto-sequencing now works correctly
|
||||||
|
|
||||||
|
|
||||||
## 0.16.0 (May 14th, 2018)
|
## 0.16.0 (May 14th, 2018)
|
||||||
|
|
||||||
BREAKING CHANGES
|
BREAKING CHANGES
|
||||||
|
@ -121,7 +135,7 @@ BREAKING CHANGES
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
|
|
||||||
* Gaia stake commands include, DeclareCandidacy, EditCandidacy, Delegate, Unbond
|
* Gaia stake commands include, CreateValidator, EditValidator, Delegate, Unbond
|
||||||
* MountStoreWithDB without providing a custom store works.
|
* MountStoreWithDB without providing a custom store works.
|
||||||
* Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI
|
* Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI
|
||||||
* Better key output, pubkey go-amino hex bytes now output by default
|
* Better key output, pubkey go-amino hex bytes now output by default
|
||||||
|
@ -137,12 +151,14 @@ BUG FIXES
|
||||||
|
|
||||||
* Gaia now uses stake, ported from github.com/cosmos/gaia
|
* Gaia now uses stake, ported from github.com/cosmos/gaia
|
||||||
|
|
||||||
|
|
||||||
## 0.15.1 (April 29, 2018)
|
## 0.15.1 (April 29, 2018)
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
|
|
||||||
* Update Tendermint to v0.19.1 (includes many rpc fixes)
|
* Update Tendermint to v0.19.1 (includes many rpc fixes)
|
||||||
|
|
||||||
|
|
||||||
## 0.15.0 (April 29, 2018)
|
## 0.15.0 (April 29, 2018)
|
||||||
|
|
||||||
NOTE: v0.15.0 is a large breaking change that updates the encoding scheme to use
|
NOTE: v0.15.0 is a large breaking change that updates the encoding scheme to use
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/btcsuite/btcd"
|
name = "github.com/btcsuite/btcd"
|
||||||
packages = ["btcec"]
|
packages = ["btcec"]
|
||||||
revision = "1432d294a5b055c297457c25434efbf13384cc46"
|
revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/cosmos/bech32cosmos"
|
name = "github.com/btcsuite/btcutil"
|
||||||
packages = ["go"]
|
packages = ["bech32"]
|
||||||
revision = "efca97cd8c0852c44d96dfdcc70565c306eddff0"
|
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/davecgh/go-spew"
|
name = "github.com/davecgh/go-spew"
|
||||||
|
@ -256,7 +256,7 @@
|
||||||
"leveldb/table",
|
"leveldb/table",
|
||||||
"leveldb/util"
|
"leveldb/util"
|
||||||
]
|
]
|
||||||
revision = "e6d6b529196422703d54ff5c40e79809ec2020b3"
|
revision = "5d6fca44a948d2be89a9702de7717f0168403d3d"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/abci"
|
name = "github.com/tendermint/abci"
|
||||||
|
@ -267,8 +267,8 @@
|
||||||
"server",
|
"server",
|
||||||
"types"
|
"types"
|
||||||
]
|
]
|
||||||
revision = "78a8905690ef54f9d57e3b2b0ee7ad3a04ef3f1f"
|
revision = "9af8b7a7c87478869f8c280ed9539470b8f470b4"
|
||||||
version = "v0.10.3"
|
version = "v0.11.0-rc4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -298,17 +298,14 @@
|
||||||
revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19"
|
revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19"
|
||||||
version = "v0.6.2"
|
version = "v0.6.2"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/tendermint/go-wire"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "fa721242b042ecd4c6ed1a934ee740db4f74e45c"
|
|
||||||
version = "v0.7.3"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/iavl"
|
name = "github.com/tendermint/iavl"
|
||||||
packages = ["."]
|
packages = [
|
||||||
revision = "fd37a0fa3a7454423233bc3d5ea828f38e0af787"
|
".",
|
||||||
version = "v0.7.0"
|
"sha256truncated"
|
||||||
|
]
|
||||||
|
revision = "c9206995e8f948e99927f5084a88a7e94ca256da"
|
||||||
|
version = "v0.8.0-rc0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/tendermint"
|
name = "github.com/tendermint/tendermint"
|
||||||
|
@ -319,6 +316,9 @@
|
||||||
"consensus",
|
"consensus",
|
||||||
"consensus/types",
|
"consensus/types",
|
||||||
"evidence",
|
"evidence",
|
||||||
|
"libs/events",
|
||||||
|
"libs/pubsub",
|
||||||
|
"libs/pubsub/query",
|
||||||
"lite",
|
"lite",
|
||||||
"lite/client",
|
"lite/client",
|
||||||
"lite/errors",
|
"lite/errors",
|
||||||
|
@ -347,13 +347,15 @@
|
||||||
"types/priv_validator",
|
"types/priv_validator",
|
||||||
"version"
|
"version"
|
||||||
]
|
]
|
||||||
revision = "018e096748bafe1d2d1e69b909e4158f3b26f6b2"
|
revision = "b5baab0238c9ec26e3b2d229b0243f9ff9220bdb"
|
||||||
version = "v0.19.5-rc1"
|
version = "v0.20.0-rc3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "develop"
|
||||||
name = "github.com/tendermint/tmlibs"
|
name = "github.com/tendermint/tmlibs"
|
||||||
packages = [
|
packages = [
|
||||||
"autofile",
|
"autofile",
|
||||||
|
"bech32",
|
||||||
"cli",
|
"cli",
|
||||||
"cli/flags",
|
"cli/flags",
|
||||||
"clist",
|
"clist",
|
||||||
|
@ -362,11 +364,9 @@
|
||||||
"flowrate",
|
"flowrate",
|
||||||
"log",
|
"log",
|
||||||
"merkle",
|
"merkle",
|
||||||
"pubsub",
|
"merkle/tmhash"
|
||||||
"pubsub/query"
|
|
||||||
]
|
]
|
||||||
revision = "cc5f287c4798ffe88c04d02df219ecb6932080fd"
|
revision = "44f1bdb0d55cc6527e38d0a7aab406e2580f56a4"
|
||||||
version = "v0.8.3-rc0"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -382,7 +382,7 @@
|
||||||
"ripemd160",
|
"ripemd160",
|
||||||
"salsa20/salsa"
|
"salsa20/salsa"
|
||||||
]
|
]
|
||||||
revision = "1a580b3eff7814fc9b40602fd35256c63b50f491"
|
revision = "5ba7f63082460102a45837dbd1827e10f9479ac0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -396,13 +396,13 @@
|
||||||
"internal/timeseries",
|
"internal/timeseries",
|
||||||
"trace"
|
"trace"
|
||||||
]
|
]
|
||||||
revision = "57065200b4b034a1c8ad54ff77069408c2218ae6"
|
revision = "1e491301e022f8f977054da4c2d852decd59571f"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["unix"]
|
packages = ["unix"]
|
||||||
revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b"
|
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
|
@ -463,6 +463,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "f0c6224dc5f30c1a7dea716d619665831ea0932b0eb9afc6ac897dbc459134fa"
|
inputs-digest = "ccb2ab7644a38c2d0326280582f758256e37fc98c3ef0403581e3b85cff42188"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
20
Gopkg.toml
20
Gopkg.toml
|
@ -54,43 +54,33 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/abci"
|
name = "github.com/tendermint/abci"
|
||||||
version = "~0.10.3"
|
version = "=0.11.0-rc4"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/go-crypto"
|
name = "github.com/tendermint/go-crypto"
|
||||||
version = "~0.6.2"
|
version = "~0.6.2"
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "github.com/tendermint/go-wire"
|
|
||||||
version = "0.7.3"
|
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/go-amino"
|
name = "github.com/tendermint/go-amino"
|
||||||
version = "~0.9.9"
|
version = "=0.9.9"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/iavl"
|
name = "github.com/tendermint/iavl"
|
||||||
version = "~0.7.0"
|
version = "0.8.0-rc0"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/tendermint"
|
name = "github.com/tendermint/tendermint"
|
||||||
version = "0.19.5-rc1"
|
version = "=0.20.0-rc3"
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/tendermint/tmlibs"
|
name = "github.com/tendermint/tmlibs"
|
||||||
version = "~0.8.3-rc0"
|
branch = "develop"
|
||||||
|
|
||||||
# this got updated and broke, so locked to an old working commit ...
|
# this got updated and broke, so locked to an old working commit ...
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "google.golang.org/genproto"
|
name = "google.golang.org/genproto"
|
||||||
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
|
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/cosmos/bech32cosmos"
|
|
||||||
branch = "master"
|
|
||||||
|
|
||||||
|
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
unused-packages = true
|
unused-packages = true
|
||||||
|
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -70,7 +70,7 @@ get_vendor_deps:
|
||||||
draw_deps:
|
draw_deps:
|
||||||
@# requires brew install graphviz or apt-get install graphviz
|
@# requires brew install graphviz or apt-get install graphviz
|
||||||
go get github.com/RobotsAndPencils/goviz
|
go get github.com/RobotsAndPencils/goviz
|
||||||
@goviz -i github.com/tendermint/tendermint/cmd/tendermint -d 3 | dot -Tpng -o dependency-graph.png
|
@goviz -i github.com/cosmos/cosmos-sdk/cmd/gaia/cmd/gaiad -d 2 | dot -Tpng -o dependency-graph.png
|
||||||
|
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
|
|
@ -68,6 +68,7 @@ type BaseApp struct {
|
||||||
checkState *state // for CheckTx
|
checkState *state // for CheckTx
|
||||||
deliverState *state // for DeliverTx
|
deliverState *state // for DeliverTx
|
||||||
valUpdates []abci.Validator // cached validator changes from DeliverTx
|
valUpdates []abci.Validator // cached validator changes from DeliverTx
|
||||||
|
signedValidators []abci.SigningValidator // absent validators from begin block
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ abci.Application = (*BaseApp)(nil)
|
var _ abci.Application = (*BaseApp)(nil)
|
||||||
|
@ -384,6 +385,8 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
||||||
if app.beginBlocker != nil {
|
if app.beginBlocker != nil {
|
||||||
res = app.beginBlocker(app.deliverState.ctx, req)
|
res = app.beginBlocker(app.deliverState.ctx, req)
|
||||||
}
|
}
|
||||||
|
// set the signed validators for addition to context in deliverTx
|
||||||
|
app.signedValidators = req.Validators
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,6 +496,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
|
||||||
ctx = app.checkState.ctx.WithTxBytes(txBytes)
|
ctx = app.checkState.ctx.WithTxBytes(txBytes)
|
||||||
} else {
|
} else {
|
||||||
ctx = app.deliverState.ctx.WithTxBytes(txBytes)
|
ctx = app.deliverState.ctx.WithTxBytes(txBytes)
|
||||||
|
ctx = ctx.WithSigningValidators(app.signedValidators)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simulate a DeliverTx for gas calculation
|
// Simulate a DeliverTx for gas calculation
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package baseapp
|
package baseapp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -12,6 +11,7 @@ import (
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -83,18 +83,36 @@ func TestLoadVersion(t *testing.T) {
|
||||||
header := abci.Header{Height: 1}
|
header := abci.Header{Height: 1}
|
||||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
res := app.Commit()
|
res := app.Commit()
|
||||||
commitID := sdk.CommitID{1, res.Data}
|
commitID1 := sdk.CommitID{1, res.Data}
|
||||||
|
header = abci.Header{Height: 2}
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
res = app.Commit()
|
||||||
|
commitID2 := sdk.CommitID{2, res.Data}
|
||||||
|
|
||||||
// reload
|
// reload with LoadLatestVersion
|
||||||
app = NewBaseApp(name, nil, logger, db)
|
app = NewBaseApp(name, nil, logger, db)
|
||||||
app.MountStoresIAVL(capKey)
|
app.MountStoresIAVL(capKey)
|
||||||
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
err = app.LoadLatestVersion(capKey)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
testLoadVersionHelper(t, app, int64(2), commitID2)
|
||||||
|
|
||||||
lastHeight = app.LastBlockHeight()
|
// reload with LoadVersion, see if you can commit the same block and get
|
||||||
lastID = app.LastCommitID()
|
// the same result
|
||||||
assert.Equal(t, int64(1), lastHeight)
|
app = NewBaseApp(name, nil, logger, db)
|
||||||
assert.Equal(t, commitID, lastID)
|
app.MountStoresIAVL(capKey)
|
||||||
|
err = app.LoadVersion(1, capKey)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
testLoadVersionHelper(t, app, int64(1), commitID1)
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
app.Commit()
|
||||||
|
testLoadVersionHelper(t, app, int64(2), commitID2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID sdk.CommitID) {
|
||||||
|
lastHeight := app.LastBlockHeight()
|
||||||
|
lastID := app.LastCommitID()
|
||||||
|
assert.Equal(t, expectedHeight, lastHeight)
|
||||||
|
assert.Equal(t, expectedID, lastID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that the app hash is static
|
// Test that the app hash is static
|
||||||
|
@ -206,11 +224,91 @@ func TestInitChainer(t *testing.T) {
|
||||||
assert.Equal(t, value, res.Value)
|
assert.Equal(t, value, res.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getStateCheckingHandler(t *testing.T, capKey *sdk.KVStoreKey, txPerHeight int, checkHeader bool) func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
|
counter := 0
|
||||||
|
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
|
store := ctx.KVStore(capKey)
|
||||||
|
// Checking state gets updated between checkTx's / DeliverTx's
|
||||||
|
// on the store within a block.
|
||||||
|
if counter > 0 {
|
||||||
|
// check previous value in store
|
||||||
|
counterBytes := []byte{byte(counter - 1)}
|
||||||
|
prevBytes := store.Get(counterBytes)
|
||||||
|
assert.Equal(t, counterBytes, prevBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the current counter in the store
|
||||||
|
counterBytes := []byte{byte(counter)}
|
||||||
|
store.Set(counterBytes, counterBytes)
|
||||||
|
|
||||||
|
// check that we can see the current header
|
||||||
|
// wrapped in an if, so it can be reused between CheckTx and DeliverTx tests.
|
||||||
|
if checkHeader {
|
||||||
|
thisHeader := ctx.BlockHeader()
|
||||||
|
height := int64((counter / txPerHeight) + 1)
|
||||||
|
assert.Equal(t, height, thisHeader.Height)
|
||||||
|
}
|
||||||
|
|
||||||
|
counter++
|
||||||
|
return sdk.Result{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A mock transaction that has a validation which can fail.
|
||||||
|
type testTx struct {
|
||||||
|
positiveNum int64
|
||||||
|
}
|
||||||
|
|
||||||
|
const msgType2 = "testTx"
|
||||||
|
|
||||||
|
func (tx testTx) Type() string { return msgType2 }
|
||||||
|
func (tx testTx) GetMsg() sdk.Msg { return tx }
|
||||||
|
func (tx testTx) GetSignBytes() []byte { return nil }
|
||||||
|
func (tx testTx) GetSigners() []sdk.Address { return nil }
|
||||||
|
func (tx testTx) GetSignatures() []auth.StdSignature { return nil }
|
||||||
|
func (tx testTx) ValidateBasic() sdk.Error {
|
||||||
|
if tx.positiveNum >= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return sdk.ErrTxDecode("positiveNum should be a non-negative integer.")
|
||||||
|
}
|
||||||
|
|
||||||
// Test that successive CheckTx can see each others' effects
|
// Test that successive CheckTx can see each others' effects
|
||||||
// on the store within a block, and that the CheckTx state
|
// on the store within a block, and that the CheckTx state
|
||||||
// gets reset to the latest Committed state during Commit
|
// gets reset to the latest Committed state during Commit
|
||||||
func TestCheckTx(t *testing.T) {
|
func TestCheckTx(t *testing.T) {
|
||||||
// TODO
|
// Initialize an app for testing
|
||||||
|
app := newBaseApp(t.Name())
|
||||||
|
// make a cap key and mount the store
|
||||||
|
capKey := sdk.NewKVStoreKey("main")
|
||||||
|
app.MountStoresIAVL(capKey)
|
||||||
|
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||||
|
assert.Nil(t, err)
|
||||||
|
app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return })
|
||||||
|
|
||||||
|
txPerHeight := 3
|
||||||
|
app.Router().AddRoute(msgType, getStateCheckingHandler(t, capKey, txPerHeight, false)).
|
||||||
|
AddRoute(msgType2, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return })
|
||||||
|
tx := testUpdatePowerTx{} // doesn't matter
|
||||||
|
for i := 0; i < txPerHeight; i++ {
|
||||||
|
app.Check(tx)
|
||||||
|
}
|
||||||
|
// If it gets to this point, then successive CheckTx's can see the effects of
|
||||||
|
// other CheckTx's on the block. The following checks that if another block
|
||||||
|
// is committed, the CheckTx State will reset.
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{})
|
||||||
|
tx2 := testTx{}
|
||||||
|
for i := 0; i < txPerHeight; i++ {
|
||||||
|
app.Deliver(tx2)
|
||||||
|
}
|
||||||
|
app.EndBlock(abci.RequestEndBlock{})
|
||||||
|
app.Commit()
|
||||||
|
|
||||||
|
checkStateStore := app.checkState.ctx.KVStore(capKey)
|
||||||
|
for i := 0; i < txPerHeight; i++ {
|
||||||
|
storedValue := checkStateStore.Get([]byte{byte(i)})
|
||||||
|
assert.Nil(t, storedValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that successive DeliverTx can see each others' effects
|
// Test that successive DeliverTx can see each others' effects
|
||||||
|
@ -224,30 +322,9 @@ func TestDeliverTx(t *testing.T) {
|
||||||
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
counter := 0
|
|
||||||
txPerHeight := 2
|
txPerHeight := 2
|
||||||
app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return })
|
app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return })
|
||||||
app.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
app.Router().AddRoute(msgType, getStateCheckingHandler(t, capKey, txPerHeight, true))
|
||||||
store := ctx.KVStore(capKey)
|
|
||||||
if counter > 0 {
|
|
||||||
// check previous value in store
|
|
||||||
counterBytes := []byte{byte(counter - 1)}
|
|
||||||
prevBytes := store.Get(counterBytes)
|
|
||||||
assert.Equal(t, prevBytes, counterBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the current counter in the store
|
|
||||||
counterBytes := []byte{byte(counter)}
|
|
||||||
store.Set(counterBytes, counterBytes)
|
|
||||||
|
|
||||||
// check we can see the current header
|
|
||||||
thisHeader := ctx.BlockHeader()
|
|
||||||
height := int64((counter / txPerHeight) + 1)
|
|
||||||
assert.Equal(t, height, thisHeader.Height)
|
|
||||||
|
|
||||||
counter++
|
|
||||||
return sdk.Result{}
|
|
||||||
})
|
|
||||||
|
|
||||||
tx := testUpdatePowerTx{} // doesn't matter
|
tx := testUpdatePowerTx{} // doesn't matter
|
||||||
header := abci.Header{AppHash: []byte("apphash")}
|
header := abci.Header{AppHash: []byte("apphash")}
|
||||||
|
@ -325,6 +402,27 @@ func TestSimulateTx(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRunInvalidTransaction(t *testing.T) {
|
||||||
|
// Initialize an app for testing
|
||||||
|
app := newBaseApp(t.Name())
|
||||||
|
// make a cap key and mount the store
|
||||||
|
capKey := sdk.NewKVStoreKey("main")
|
||||||
|
app.MountStoresIAVL(capKey)
|
||||||
|
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||||
|
assert.Nil(t, err)
|
||||||
|
app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return })
|
||||||
|
app.Router().AddRoute(msgType2, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return })
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{})
|
||||||
|
// Transaction where validate fails
|
||||||
|
invalidTx := testTx{-1}
|
||||||
|
err1 := app.Deliver(invalidTx)
|
||||||
|
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeTxDecode), err1.Code)
|
||||||
|
// Transaction with no known route
|
||||||
|
unknownRouteTx := testUpdatePowerTx{}
|
||||||
|
err2 := app.Deliver(unknownRouteTx)
|
||||||
|
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), err2.Code)
|
||||||
|
}
|
||||||
|
|
||||||
// Test that transactions exceeding gas limits fail
|
// Test that transactions exceeding gas limits fail
|
||||||
func TestTxGasLimits(t *testing.T) {
|
func TestTxGasLimits(t *testing.T) {
|
||||||
logger := defaultLogger()
|
logger := defaultLogger()
|
||||||
|
@ -510,15 +608,20 @@ func TestValidatorChange(t *testing.T) {
|
||||||
|
|
||||||
// Assert that validator updates are correct.
|
// Assert that validator updates are correct.
|
||||||
for _, val := range valSet {
|
for _, val := range valSet {
|
||||||
|
|
||||||
|
pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey)
|
||||||
// Sanity
|
// Sanity
|
||||||
assert.NotEqual(t, len(val.PubKey), 0)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// Find matching update and splice it out.
|
// Find matching update and splice it out.
|
||||||
for j := 0; j < len(valUpdates); {
|
for j := 0; j < len(valUpdates); j++ {
|
||||||
valUpdate := valUpdates[j]
|
valUpdate := valUpdates[j]
|
||||||
|
|
||||||
|
updatePubkey, err := tmtypes.PB2TM.PubKey(valUpdate.PubKey)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// Matched.
|
// Matched.
|
||||||
if bytes.Equal(valUpdate.PubKey, val.PubKey) {
|
if updatePubkey.Equals(pubkey) {
|
||||||
assert.Equal(t, valUpdate.Power, val.Power+1)
|
assert.Equal(t, valUpdate.Power, val.Power+1)
|
||||||
if j < len(valUpdates)-1 {
|
if j < len(valUpdates)-1 {
|
||||||
// Splice it out.
|
// Splice it out.
|
||||||
|
@ -528,7 +631,6 @@ func TestValidatorChange(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not matched.
|
// Not matched.
|
||||||
j++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.Equal(t, len(valUpdates), 0, "Some validator updates were unexpected")
|
assert.Equal(t, len(valUpdates), 0, "Some validator updates were unexpected")
|
||||||
|
@ -542,7 +644,7 @@ func randPower() int64 {
|
||||||
|
|
||||||
func makeVal(secret string) abci.Validator {
|
func makeVal(secret string) abci.Validator {
|
||||||
return abci.Validator{
|
return abci.Validator{
|
||||||
PubKey: makePubKey(secret).Bytes(),
|
PubKey: tmtypes.TM2PB.PubKey(makePubKey(secret)),
|
||||||
Power: randPower(),
|
Power: randPower(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (ctx CoreContext) QuerySubspace(cdc *wire.Codec, subspace []byte, storeName
|
||||||
|
|
||||||
// Query from Tendermint with the provided storename and path
|
// Query from Tendermint with the provided storename and path
|
||||||
func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) {
|
func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) {
|
||||||
path := fmt.Sprintf("/store/%s/key", storeName)
|
path := fmt.Sprintf("/store/%s/%s", storeName, endPath)
|
||||||
node, err := ctx.GetNode()
|
node, err := ctx.GetNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -102,12 +102,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
|
||||||
return nil
|
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) {
|
func printCreate(info keys.Info, seed string) {
|
||||||
output := viper.Get(cli.OutputFlag)
|
output := viper.Get(cli.OutputFlag)
|
||||||
switch output {
|
switch output {
|
||||||
|
@ -121,7 +115,10 @@ func printCreate(info keys.Info, seed string) {
|
||||||
fmt.Println(seed)
|
fmt.Println(seed)
|
||||||
}
|
}
|
||||||
case "json":
|
case "json":
|
||||||
out := addOutput{Key: info}
|
out, err := Bech32KeyOutput(info)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
if !viper.GetBool(flagNoBackup) {
|
if !viper.GetBool(flagNoBackup) {
|
||||||
out.Seed = seed
|
out.Seed = seed
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,9 +53,11 @@ func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write([]byte("[]"))
|
w.Write([]byte("[]"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keysOutput := make([]KeyOutput, len(infos))
|
keysOutput, err := Bech32KeysOutput(infos)
|
||||||
for i, info := range infos {
|
if err != nil {
|
||||||
keysOutput[i] = KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address().Bytes())}
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
output, err := json.MarshalIndent(keysOutput, "", " ")
|
output, err := json.MarshalIndent(keysOutput, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
keys "github.com/tendermint/go-crypto/keys"
|
keys "github.com/tendermint/go-crypto/keys"
|
||||||
|
|
||||||
|
@ -51,7 +50,12 @@ func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
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, "", " ")
|
output, err := json.MarshalIndent(keyOutput, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package keys
|
package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
keys "github.com/tendermint/go-crypto/keys"
|
keys "github.com/tendermint/go-crypto/keys"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
|
@ -49,34 +47,52 @@ func SetKeyBase(kb keys.Keybase) {
|
||||||
// used for outputting keys.Info over REST
|
// used for outputting keys.Info over REST
|
||||||
type KeyOutput struct {
|
type KeyOutput struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Address sdk.Address `json:"address"`
|
Address string `json:"address"`
|
||||||
PubKey crypto.PubKey `json:"pub_key"`
|
PubKey string `json:"pub_key"`
|
||||||
|
Seed string `json:"seed,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKeyOutput(info keys.Info) KeyOutput {
|
// create a list of KeyOutput in bech32 format
|
||||||
return KeyOutput{
|
func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) {
|
||||||
Name: info.Name,
|
|
||||||
Address: sdk.Address(info.PubKey.Address().Bytes()),
|
|
||||||
PubKey: info.PubKey,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyOutputs(infos []keys.Info) []KeyOutput {
|
|
||||||
kos := make([]KeyOutput, len(infos))
|
kos := make([]KeyOutput, len(infos))
|
||||||
for i, info := range infos {
|
for i, info := range infos {
|
||||||
kos[i] = NewKeyOutput(info)
|
ko, err := Bech32KeyOutput(info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return kos
|
kos[i] = ko
|
||||||
|
}
|
||||||
|
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) {
|
func printInfo(info keys.Info) {
|
||||||
ko := NewKeyOutput(info)
|
ko, err := Bech32KeyOutput(info)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
switch viper.Get(cli.OutputFlag) {
|
switch viper.Get(cli.OutputFlag) {
|
||||||
case "text":
|
case "text":
|
||||||
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
||||||
printKeyOutput(ko)
|
printKeyOutput(ko)
|
||||||
case "json":
|
case "json":
|
||||||
out, err := json.MarshalIndent(ko, "", "\t")
|
out, err := MarshalJSON(ko)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +101,10 @@ func printInfo(info keys.Info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printInfos(infos []keys.Info) {
|
func printInfos(infos []keys.Info) {
|
||||||
kos := NewKeyOutputs(infos)
|
kos, err := Bech32KeysOutput(infos)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
switch viper.Get(cli.OutputFlag) {
|
switch viper.Get(cli.OutputFlag) {
|
||||||
case "text":
|
case "text":
|
||||||
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
||||||
|
@ -93,7 +112,7 @@ func printInfos(infos []keys.Info) {
|
||||||
printKeyOutput(ko)
|
printKeyOutput(ko)
|
||||||
}
|
}
|
||||||
case "json":
|
case "json":
|
||||||
out, err := json.MarshalIndent(kos, "", "\t")
|
out, err := MarshalJSON(kos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -102,13 +121,5 @@ func printInfos(infos []keys.Info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printKeyOutput(ko KeyOutput) {
|
func printKeyOutput(ko KeyOutput) {
|
||||||
bechAccount, err := sdk.Bech32CosmosifyAcc(ko.Address)
|
fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
bechPubKey, err := sdk.Bech32CosmosifyAccPub(ko.PubKey)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Printf("%s\t%s\t%s\n", ko.Name, bechAccount, bechPubKey)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package lcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -16,6 +17,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
cryptoKeys "github.com/tendermint/go-crypto/keys"
|
cryptoKeys "github.com/tendermint/go-crypto/keys"
|
||||||
tmcfg "github.com/tendermint/tendermint/config"
|
tmcfg "github.com/tendermint/tendermint/config"
|
||||||
nm "github.com/tendermint/tendermint/node"
|
nm "github.com/tendermint/tendermint/node"
|
||||||
|
@ -31,21 +33,30 @@ import (
|
||||||
|
|
||||||
client "github.com/cosmos/cosmos-sdk/client"
|
client "github.com/cosmos/cosmos-sdk/client"
|
||||||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
bapp "github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
||||||
btypes "github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
tests "github.com/cosmos/cosmos-sdk/tests"
|
tests "github.com/cosmos/cosmos-sdk/tests"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
coinDenom = "mycoin"
|
coinDenom = "steak"
|
||||||
coinAmount = int64(10000000)
|
coinAmount = int64(10000000)
|
||||||
|
|
||||||
|
validatorAddr1Hx = ""
|
||||||
|
validatorAddr2Hx = ""
|
||||||
|
validatorAddr1 = ""
|
||||||
|
validatorAddr2 = ""
|
||||||
|
|
||||||
// XXX bad globals
|
// XXX bad globals
|
||||||
name = "test"
|
name = "test"
|
||||||
password = "0123456789"
|
password = "0123456789"
|
||||||
port string // XXX: but it's the int ...
|
port string
|
||||||
seed string
|
seed string
|
||||||
sendAddr string
|
sendAddr string
|
||||||
)
|
)
|
||||||
|
@ -92,13 +103,13 @@ func TestKeys(t *testing.T) {
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &m)
|
err = cdc.UnmarshalJSON([]byte(body), &m)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
sendAddrAcc, _ := sdk.GetAccAddressHex(sendAddr)
|
|
||||||
addrAcc, _ := sdk.GetAccAddressHex(addr)
|
addrAcc, _ := sdk.GetAccAddressHex(addr)
|
||||||
|
addrBech32, _ := sdk.Bech32ifyAcc(addrAcc)
|
||||||
|
|
||||||
assert.Equal(t, m[0].Name, name, "Did not serve keys name correctly")
|
assert.Equal(t, name, m[0].Name, "Did not serve keys name correctly")
|
||||||
assert.Equal(t, m[0].Address, sendAddrAcc, "Did not serve keys Address correctly")
|
assert.Equal(t, sendAddr, m[0].Address, "Did not serve keys Address correctly")
|
||||||
assert.Equal(t, m[1].Name, newName, "Did not serve keys name correctly")
|
assert.Equal(t, newName, m[1].Name, "Did not serve keys name correctly")
|
||||||
assert.Equal(t, m[1].Address, addrAcc, "Did not serve keys Address correctly")
|
assert.Equal(t, addrBech32, m[1].Address, "Did not serve keys Address correctly")
|
||||||
|
|
||||||
// select key
|
// select key
|
||||||
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
|
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
|
||||||
|
@ -109,7 +120,7 @@ func TestKeys(t *testing.T) {
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
|
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, addrBech32, m2.Address, "Did not serve keys Address correctly")
|
||||||
|
|
||||||
// update key
|
// update key
|
||||||
jsonStr = []byte(fmt.Sprintf(`{"old_password":"%s", "new_password":"12345678901"}`, newPassword))
|
jsonStr = []byte(fmt.Sprintf(`{"old_password":"%s", "new_password":"12345678901"}`, newPassword))
|
||||||
|
@ -191,7 +202,7 @@ func TestBlock(t *testing.T) {
|
||||||
|
|
||||||
func TestValidators(t *testing.T) {
|
func TestValidators(t *testing.T) {
|
||||||
|
|
||||||
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)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
@ -199,7 +210,10 @@ func TestValidators(t *testing.T) {
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &resultVals)
|
err := cdc.UnmarshalJSON([]byte(body), &resultVals)
|
||||||
require.Nil(t, err, "Couldn't parse validatorset")
|
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")
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
|
@ -209,7 +223,7 @@ func TestValidators(t *testing.T) {
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &resultVals)
|
err = cdc.UnmarshalJSON([]byte(body), &resultVals)
|
||||||
require.Nil(t, err, "Couldn't parse validatorset")
|
require.Nil(t, err, "Couldn't parse validatorset")
|
||||||
|
|
||||||
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals)
|
assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
|
@ -218,9 +232,11 @@ func TestValidators(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCoinSend(t *testing.T) {
|
func TestCoinSend(t *testing.T) {
|
||||||
|
bz, _ := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6")
|
||||||
|
someFakeAddr, _ := sdk.Bech32ifyAcc(bz)
|
||||||
|
|
||||||
// query empty
|
// query empty
|
||||||
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)
|
require.Equal(t, http.StatusNoContent, res.StatusCode, body)
|
||||||
|
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, sendAddr)
|
||||||
|
@ -309,6 +325,62 @@ func TestTxs(t *testing.T) {
|
||||||
// assert.NotEqual(t, "[]", body)
|
// assert.NotEqual(t, "[]", body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidatorsQuery(t *testing.T) {
|
||||||
|
validators := getValidators(t)
|
||||||
|
assert.Equal(t, len(validators), 2)
|
||||||
|
|
||||||
|
// make sure all the validators were found (order unknown because sorted by owner addr)
|
||||||
|
foundVal1, foundVal2 := false, false
|
||||||
|
if validators[0].Owner == validatorAddr1 || validators[1].Owner == validatorAddr1 {
|
||||||
|
foundVal1 = true
|
||||||
|
}
|
||||||
|
if validators[0].Owner == validatorAddr2 || validators[1].Owner == validatorAddr2 {
|
||||||
|
foundVal2 = true
|
||||||
|
}
|
||||||
|
assert.True(t, foundVal1, "validatorAddr1 %v, owner1 %v, owner2 %v", validatorAddr1, validators[0].Owner, validators[1].Owner)
|
||||||
|
assert.True(t, foundVal2, "validatorAddr2 %v, owner1 %v, owner2 %v", validatorAddr2, validators[0].Owner, validators[1].Owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBond(t *testing.T) {
|
||||||
|
|
||||||
|
// create bond TX
|
||||||
|
resultTx := doBond(t, port, seed)
|
||||||
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
// check if tx was commited
|
||||||
|
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||||
|
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||||
|
|
||||||
|
// query sender
|
||||||
|
acc := getAccount(t, sendAddr)
|
||||||
|
coins := acc.GetCoins()
|
||||||
|
assert.Equal(t, int64(87), coins.AmountOf(coinDenom))
|
||||||
|
|
||||||
|
// query candidate
|
||||||
|
bond := getDelegation(t, sendAddr, validatorAddr1)
|
||||||
|
assert.Equal(t, "10/1", bond.Shares.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnbond(t *testing.T) {
|
||||||
|
|
||||||
|
// create unbond TX
|
||||||
|
resultTx := doUnbond(t, port, seed)
|
||||||
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
// check if tx was commited
|
||||||
|
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||||
|
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||||
|
|
||||||
|
// query sender
|
||||||
|
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
|
// helpers
|
||||||
|
|
||||||
|
@ -324,26 +396,18 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
var info cryptoKeys.Info
|
|
||||||
info, seed, err = kb.Create(name, password, cryptoKeys.AlgoEd25519) // XXX global seed
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pubKey := info.PubKey
|
|
||||||
sendAddr = pubKey.Address().String() // XXX global
|
|
||||||
|
|
||||||
config := GetConfig()
|
config := GetConfig()
|
||||||
config.Consensus.TimeoutCommit = 1000
|
config.Consensus.TimeoutCommit = 1000
|
||||||
config.Consensus.SkipTimeoutCommit = false
|
config.Consensus.SkipTimeoutCommit = false
|
||||||
|
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||||
// logger = log.NewFilter(logger, log.AllowError())
|
logger = log.NewFilter(logger, log.AllowError())
|
||||||
privValidatorFile := config.PrivValidatorFile()
|
privValidatorFile := config.PrivValidatorFile()
|
||||||
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
|
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
app := bapp.NewBasecoinApp(logger, db)
|
app := gapp.NewGaiaApp(logger, db)
|
||||||
cdc = bapp.MakeCodec() // XXX
|
cdc = gapp.MakeCodec() // XXX
|
||||||
|
|
||||||
genesisFile := config.GenesisFile()
|
genesisFile := config.GenesisFile()
|
||||||
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
||||||
|
@ -351,25 +415,63 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
coins := sdk.Coins{{coinDenom, coinAmount}}
|
genDoc.Validators = append(genDoc.Validators,
|
||||||
appState := map[string]interface{}{
|
tmtypes.GenesisValidator{
|
||||||
"accounts": []*btypes.GenesisAccount{
|
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
|
||||||
{
|
Power: 1,
|
||||||
Name: "tester",
|
Name: "val",
|
||||||
Address: pubKey.Address(),
|
|
||||||
Coins: coins,
|
|
||||||
},
|
},
|
||||||
},
|
)
|
||||||
}
|
|
||||||
stateBytes, err := json.Marshal(appState)
|
pk1 := genDoc.Validators[0].PubKey
|
||||||
|
pk2 := genDoc.Validators[1].PubKey
|
||||||
|
validatorAddr1Hx = hex.EncodeToString(pk1.Address())
|
||||||
|
validatorAddr2Hx = hex.EncodeToString(pk2.Address())
|
||||||
|
validatorAddr1, _ = sdk.Bech32ifyVal(pk1.Address())
|
||||||
|
validatorAddr2, _ = sdk.Bech32ifyVal(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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
genDoc.AppStateJSON = stateBytes
|
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
|
||||||
|
}
|
||||||
|
sendAddrHex, _ := sdk.GetAccAddressHex(info.PubKey.Address().String())
|
||||||
|
sendAddr, _ = sdk.Bech32ifyAcc(sendAddrHex) // 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
|
// LCD listen address
|
||||||
port = fmt.Sprintf("%d", 17377) // XXX
|
var listenAddr string
|
||||||
listenAddr := fmt.Sprintf("tcp://localhost:%s", port) // XXX
|
listenAddr, port, err = server.FreeTCPAddr()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: need to set this so LCD knows the tendermint node address!
|
// XXX: need to set this so LCD knows the tendermint node address!
|
||||||
viper.Set(client.FlagNode, config.RPC.ListenAddress)
|
viper.Set(client.FlagNode, config.RPC.ListenAddress)
|
||||||
|
@ -379,7 +481,7 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
lcd, err := startLCD(logger, listenAddr)
|
lcd, err := startLCD(logger, listenAddr, cdc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -418,7 +520,7 @@ func startTM(cfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, p
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the LCD. note this blocks!
|
// start the LCD. note this blocks!
|
||||||
func startLCD(logger log.Logger, listenAddr string) (net.Listener, error) {
|
func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) {
|
||||||
handler := createHandler(cdc)
|
handler := createHandler(cdc)
|
||||||
return tmrpc.StartHTTPServer(listenAddr, handler, logger)
|
return tmrpc.StartHTTPServer(listenAddr, handler, logger)
|
||||||
}
|
}
|
||||||
|
@ -456,7 +558,7 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
|
||||||
kb := client.MockKeyBase()
|
kb := client.MockKeyBase()
|
||||||
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
receiveAddr = receiveInfo.PubKey.Address().String()
|
receiveAddr, _ = sdk.Bech32ifyAcc(receiveInfo.PubKey.Address())
|
||||||
|
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, sendAddr)
|
||||||
sequence := acc.GetSequence()
|
sequence := acc.GetSequence()
|
||||||
|
@ -473,12 +575,11 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
|
||||||
}
|
}
|
||||||
|
|
||||||
func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
|
|
||||||
// create receive address
|
// create receive address
|
||||||
kb := client.MockKeyBase()
|
kb := client.MockKeyBase()
|
||||||
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
receiveAddr := receiveInfo.PubKey.Address().String()
|
receiveAddr, _ := sdk.Bech32ifyAcc(receiveInfo.PubKey.Address())
|
||||||
|
|
||||||
// get the account to get the sequence
|
// get the account to get the sequence
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, sendAddr)
|
||||||
|
@ -494,3 +595,81 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad
|
||||||
|
|
||||||
return resultTx
|
return resultTx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDelegation(t *testing.T, delegatorAddr, candidateAddr string) stake.Delegation {
|
||||||
|
// get the account to get the sequence
|
||||||
|
res, body := request(t, port, "GET", "/stake/"+delegatorAddr+"/bonding_status/"+candidateAddr, nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
var bond stake.Delegation
|
||||||
|
err := cdc.UnmarshalJSON([]byte(body), &bond)
|
||||||
|
require.Nil(t, err)
|
||||||
|
return bond
|
||||||
|
}
|
||||||
|
|
||||||
|
func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
|
// get the account to get the sequence
|
||||||
|
acc := getAccount(t, sendAddr)
|
||||||
|
sequence := acc.GetSequence()
|
||||||
|
|
||||||
|
// send
|
||||||
|
jsonStr := []byte(fmt.Sprintf(`{
|
||||||
|
"name": "%s",
|
||||||
|
"password": "%s",
|
||||||
|
"sequence": %d,
|
||||||
|
"delegate": [
|
||||||
|
{
|
||||||
|
"delegator_addr": "%s",
|
||||||
|
"validator_addr": "%s",
|
||||||
|
"bond": { "denom": "%s", "amount": 10 }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"unbond": []
|
||||||
|
}`, name, password, sequence, sendAddr, validatorAddr1, coinDenom))
|
||||||
|
res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
var results []ctypes.ResultBroadcastTxCommit
|
||||||
|
err := cdc.UnmarshalJSON([]byte(body), &results)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
return results[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
|
// get the account to get the sequence
|
||||||
|
acc := getAccount(t, sendAddr)
|
||||||
|
sequence := acc.GetSequence()
|
||||||
|
|
||||||
|
// send
|
||||||
|
jsonStr := []byte(fmt.Sprintf(`{
|
||||||
|
"name": "%s",
|
||||||
|
"password": "%s",
|
||||||
|
"sequence": %d,
|
||||||
|
"bond": [],
|
||||||
|
"unbond": [
|
||||||
|
{
|
||||||
|
"delegator_addr": "%s",
|
||||||
|
"validator_addr": "%s",
|
||||||
|
"shares": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, name, password, sequence, sendAddr, validatorAddr1))
|
||||||
|
res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
var results []ctypes.ResultBroadcastTxCommit
|
||||||
|
err := cdc.UnmarshalJSON([]byte(body), &results)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
return results[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func getValidators(t *testing.T) []stakerest.StakeValidatorOutput {
|
||||||
|
// get the account to get the sequence
|
||||||
|
res, body := request(t, port, "GET", "/stake/validators", nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
var validators []stakerest.StakeValidatorOutput
|
||||||
|
err := cdc.UnmarshalJSON([]byte(body), &validators)
|
||||||
|
require.Nil(t, err)
|
||||||
|
return validators
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||||
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||||
ibc "github.com/cosmos/cosmos-sdk/x/ibc/client/rest"
|
ibc "github.com/cosmos/cosmos-sdk/x/ibc/client/rest"
|
||||||
|
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -55,6 +56,7 @@ func startRESTServerFn(cdc *wire.Codec) func(cmd *cobra.Command, args []string)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
logger.Info("REST server started")
|
||||||
|
|
||||||
// Wait forever and cleanup
|
// Wait forever and cleanup
|
||||||
cmn.TrapSignal(func() {
|
cmn.TrapSignal(func() {
|
||||||
|
@ -83,5 +85,6 @@ func createHandler(cdc *wire.Codec) http.Handler {
|
||||||
auth.RegisterRoutes(ctx, r, cdc, "acc")
|
auth.RegisterRoutes(ctx, r, cdc, "acc")
|
||||||
bank.RegisterRoutes(ctx, r, cdc, kb)
|
bank.RegisterRoutes(ctx, r, cdc, kb)
|
||||||
ibc.RegisterRoutes(ctx, r, cdc, kb)
|
ibc.RegisterRoutes(ctx, r, cdc, kb)
|
||||||
|
stake.RegisterRoutes(ctx, r, cdc, kb)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ const (
|
||||||
flagSelect = "select"
|
flagSelect = "select"
|
||||||
)
|
)
|
||||||
|
|
||||||
func blockCommand() *cobra.Command {
|
//BlockCommand returns the verified block data for a given heights
|
||||||
|
func BlockCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "block [height]",
|
Use: "block [height]",
|
||||||
Short: "Get verified data for a the block at given height",
|
Short: "Get verified data for a the block at given height",
|
||||||
|
|
|
@ -26,8 +26,6 @@ func AddCommands(cmd *cobra.Command) {
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
initClientCommand(),
|
initClientCommand(),
|
||||||
statusCommand(),
|
statusCommand(),
|
||||||
blockCommand(),
|
|
||||||
validatorCommand(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,17 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"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
|
// TODO these next two functions feel kinda hacky based on their placement
|
||||||
|
|
||||||
func validatorCommand() *cobra.Command {
|
//ValidatorCommand returns the validator set for a given height
|
||||||
|
func ValidatorCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "validatorset [height]",
|
Use: "validator-set [height]",
|
||||||
Short: "Get the full validator set at given height",
|
Short: "Get the full tendermint validator set at given height",
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
RunE: printValidators,
|
RunE: printValidators,
|
||||||
}
|
}
|
||||||
|
@ -27,6 +30,38 @@ func validatorCommand() *cobra.Command {
|
||||||
return cmd
|
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) {
|
func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
|
||||||
// get the node
|
// get the node
|
||||||
node, err := ctx.GetNode()
|
node, err := ctx.GetNode()
|
||||||
|
@ -34,12 +69,23 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := node.Validators(height)
|
validatorsRes, err := node.Validators(height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -95,6 +141,7 @@ func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(output)
|
w.Write(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -15,6 +16,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,6 +40,7 @@ type GaiaApp struct {
|
||||||
keyAccount *sdk.KVStoreKey
|
keyAccount *sdk.KVStoreKey
|
||||||
keyIBC *sdk.KVStoreKey
|
keyIBC *sdk.KVStoreKey
|
||||||
keyStake *sdk.KVStoreKey
|
keyStake *sdk.KVStoreKey
|
||||||
|
keySlashing *sdk.KVStoreKey
|
||||||
|
|
||||||
// Manage getting and setting accounts
|
// Manage getting and setting accounts
|
||||||
accountMapper auth.AccountMapper
|
accountMapper auth.AccountMapper
|
||||||
|
@ -45,6 +48,7 @@ type GaiaApp struct {
|
||||||
coinKeeper bank.Keeper
|
coinKeeper bank.Keeper
|
||||||
ibcMapper ibc.Mapper
|
ibcMapper ibc.Mapper
|
||||||
stakeKeeper stake.Keeper
|
stakeKeeper stake.Keeper
|
||||||
|
slashingKeeper slashing.Keeper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
||||||
|
@ -58,6 +62,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
||||||
keyAccount: sdk.NewKVStoreKey("acc"),
|
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||||
keyIBC: sdk.NewKVStoreKey("ibc"),
|
keyIBC: sdk.NewKVStoreKey("ibc"),
|
||||||
keyStake: sdk.NewKVStoreKey("stake"),
|
keyStake: sdk.NewKVStoreKey("stake"),
|
||||||
|
keySlashing: sdk.NewKVStoreKey("slashing"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// define the accountMapper
|
// define the accountMapper
|
||||||
|
@ -71,6 +76,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
||||||
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
||||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
|
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.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
|
// register message routes
|
||||||
app.Router().
|
app.Router().
|
||||||
|
@ -80,9 +86,10 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
||||||
|
|
||||||
// initialize BaseApp
|
// initialize BaseApp
|
||||||
app.SetInitChainer(app.initChainer)
|
app.SetInitChainer(app.initChainer)
|
||||||
app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper))
|
app.SetBeginBlocker(app.BeginBlocker)
|
||||||
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake)
|
app.SetEndBlocker(app.EndBlocker)
|
||||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
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)
|
err := app.LoadLatestVersion(app.keyMain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmn.Exit(err.Error())
|
cmn.Exit(err.Error())
|
||||||
|
@ -97,15 +104,35 @@ func MakeCodec() *wire.Codec {
|
||||||
ibc.RegisterWire(cdc)
|
ibc.RegisterWire(cdc)
|
||||||
bank.RegisterWire(cdc)
|
bank.RegisterWire(cdc)
|
||||||
stake.RegisterWire(cdc)
|
stake.RegisterWire(cdc)
|
||||||
|
slashing.RegisterWire(cdc)
|
||||||
auth.RegisterWire(cdc)
|
auth.RegisterWire(cdc)
|
||||||
sdk.RegisterWire(cdc)
|
sdk.RegisterWire(cdc)
|
||||||
wire.RegisterCrypto(cdc)
|
wire.RegisterCrypto(cdc)
|
||||||
return 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
|
// custom logic for gaia initialization
|
||||||
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||||
stateJSON := req.AppStateBytes
|
stateJSON := req.AppStateBytes
|
||||||
|
// TODO is this now the whole genesis file?
|
||||||
|
|
||||||
var genesisState GenesisState
|
var genesisState GenesisState
|
||||||
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
|
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
|
||||||
|
@ -126,8 +153,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
||||||
return abci.ResponseInitChain{}
|
return abci.ResponseInitChain{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// export the state of gaia for a genesis f
|
// 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{})
|
ctx := app.NewContext(true, abci.Header{})
|
||||||
|
|
||||||
// iterate to get the accounts
|
// iterate to get the accounts
|
||||||
|
@ -143,5 +170,10 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
||||||
Accounts: accounts,
|
Accounts: accounts,
|
||||||
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -115,7 +114,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
||||||
|
|
||||||
// Initialize the chain
|
// Initialize the chain
|
||||||
vals := []abci.Validator{}
|
vals := []abci.Validator{}
|
||||||
gapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
gapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||||
gapp.Commit()
|
gapp.Commit()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -139,30 +138,6 @@ func TestMsgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setGenesisAccounts(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
|
||||||
genaccs := make([]GenesisAccount, len(accs))
|
|
||||||
for i, acc := range accs {
|
|
||||||
genaccs[i] = NewGenesisAccount(acc)
|
|
||||||
}
|
|
||||||
|
|
||||||
genesisState := GenesisState{
|
|
||||||
Accounts: genaccs,
|
|
||||||
StakeData: stake.DefaultGenesisState(),
|
|
||||||
}
|
|
||||||
|
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the chain
|
|
||||||
vals := []abci.Validator{}
|
|
||||||
gapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
|
||||||
gapp.Commit()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenesis(t *testing.T) {
|
func TestGenesis(t *testing.T) {
|
||||||
logger, dbs := loggerAndDB()
|
logger, dbs := loggerAndDB()
|
||||||
gapp := NewGaiaApp(logger, dbs)
|
gapp := NewGaiaApp(logger, dbs)
|
||||||
|
@ -178,7 +153,7 @@ func TestGenesis(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setGenesis(gapp, baseAcc)
|
err = setGenesis(gapp, baseAcc)
|
||||||
assert.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
// A checkTx context
|
// A checkTx context
|
||||||
ctx := gapp.BaseApp.NewContext(true, abci.Header{})
|
ctx := gapp.BaseApp.NewContext(true, abci.Header{})
|
||||||
|
@ -394,13 +369,13 @@ func TestStakeMsgs(t *testing.T) {
|
||||||
require.Equal(t, acc1, res1)
|
require.Equal(t, acc1, res1)
|
||||||
require.Equal(t, acc2, res2)
|
require.Equal(t, acc2, res2)
|
||||||
|
|
||||||
// Declare Candidacy
|
// Create Validator
|
||||||
|
|
||||||
description := stake.NewDescription("foo_moniker", "", "", "")
|
description := stake.NewDescription("foo_moniker", "", "", "")
|
||||||
declareCandidacyMsg := stake.NewMsgDeclareCandidacy(
|
createValidatorMsg := stake.NewMsgCreateValidator(
|
||||||
addr1, priv1.PubKey(), bondCoin, description,
|
addr1, priv1.PubKey(), bondCoin, description,
|
||||||
)
|
)
|
||||||
SignCheckDeliver(t, gapp, declareCandidacyMsg, []int64{0}, true, priv1)
|
SignCheckDeliver(t, gapp, createValidatorMsg, []int64{0}, true, priv1)
|
||||||
|
|
||||||
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
|
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
|
||||||
res1 = gapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
res1 = gapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||||
|
@ -415,13 +390,13 @@ func TestStakeMsgs(t *testing.T) {
|
||||||
bond, found := gapp.stakeKeeper.GetDelegation(ctxDeliver, addr1, addr1)
|
bond, found := gapp.stakeKeeper.GetDelegation(ctxDeliver, addr1, addr1)
|
||||||
require.True(sdk.RatEq(t, sdk.NewRat(10), bond.Shares))
|
require.True(sdk.RatEq(t, sdk.NewRat(10), bond.Shares))
|
||||||
|
|
||||||
// Edit Candidacy
|
// Edit Validator
|
||||||
|
|
||||||
description = stake.NewDescription("bar_moniker", "", "", "")
|
description = stake.NewDescription("bar_moniker", "", "", "")
|
||||||
editCandidacyMsg := stake.NewMsgEditCandidacy(
|
editValidatorMsg := stake.NewMsgEditValidator(
|
||||||
addr1, description,
|
addr1, description,
|
||||||
)
|
)
|
||||||
SignDeliver(t, gapp, editCandidacyMsg, []int64{1}, true, priv1)
|
SignDeliver(t, gapp, editValidatorMsg, []int64{1}, true, priv1)
|
||||||
|
|
||||||
validator, found = gapp.stakeKeeper.GetValidator(ctxDeliver, addr1)
|
validator, found = gapp.stakeKeeper.GetValidator(ctxDeliver, addr1)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
|
@ -455,6 +430,42 @@ func TestStakeMsgs(t *testing.T) {
|
||||||
require.False(t, found)
|
require.False(t, found)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExportValidators(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)
|
||||||
|
|
||||||
|
// Create Validator
|
||||||
|
description := stake.NewDescription("foo_moniker", "", "", "")
|
||||||
|
createValidatorMsg := stake.NewMsgCreateValidator(
|
||||||
|
addr1, priv1.PubKey(), bondCoin, description,
|
||||||
|
)
|
||||||
|
SignCheckDeliver(t, gapp, createValidatorMsg, []int64{0}, true, priv1)
|
||||||
|
gapp.Commit()
|
||||||
|
|
||||||
|
// Export validator set
|
||||||
|
_, validators, err := gapp.ExportAppStateAndValidators()
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, 1, len(validators)) // 1 validator
|
||||||
|
require.Equal(t, priv1.PubKey(), validators[0].PubKey)
|
||||||
|
require.Equal(t, int64(10), validators[0].Power)
|
||||||
|
}
|
||||||
|
|
||||||
//____________________________________________________________________________________
|
//____________________________________________________________________________________
|
||||||
|
|
||||||
func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) {
|
func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) {
|
||||||
|
|
|
@ -65,7 +65,7 @@ func GaiaAppInit() server.AppInit {
|
||||||
fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError)
|
fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||||
|
|
||||||
fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError)
|
fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||||
fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator")
|
fsAppGenTx.String(flagName, "", "validator moniker, required")
|
||||||
fsAppGenTx.String(flagClientHome, DefaultCLIHome,
|
fsAppGenTx.String(flagClientHome, DefaultCLIHome,
|
||||||
"home directory for the client, used for key generation")
|
"home directory for the client, used for key generation")
|
||||||
fsAppGenTx.Bool(flagOWK, false, "overwrite the accounts created")
|
fsAppGenTx.Bool(flagOWK, false, "overwrite the accounts created")
|
||||||
|
@ -74,7 +74,7 @@ func GaiaAppInit() server.AppInit {
|
||||||
FlagsAppGenState: fsAppGenState,
|
FlagsAppGenState: fsAppGenState,
|
||||||
FlagsAppGenTx: fsAppGenTx,
|
FlagsAppGenTx: fsAppGenTx,
|
||||||
AppGenTx: GaiaAppGenTx,
|
AppGenTx: GaiaAppGenTx,
|
||||||
AppGenState: GaiaAppGenState,
|
AppGenState: GaiaAppGenStateJSON,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,19 +85,35 @@ type GaiaGenTx struct {
|
||||||
PubKey crypto.PubKey `json:"pub_key"`
|
PubKey crypto.PubKey `json:"pub_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a gaia genesis transaction
|
// Generate a gaia genesis transaction with flags
|
||||||
func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
||||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||||
|
|
||||||
var addr sdk.Address
|
|
||||||
var secret string
|
|
||||||
clientRoot := viper.GetString(flagClientHome)
|
clientRoot := viper.GetString(flagClientHome)
|
||||||
overwrite := viper.GetBool(flagOWK)
|
overwrite := viper.GetBool(flagOWK)
|
||||||
name := viper.GetString(flagName)
|
name := viper.GetString(flagName)
|
||||||
|
if name == "" {
|
||||||
|
return nil, nil, tmtypes.GenesisValidator{}, errors.New("Must specify --name (validator moniker)")
|
||||||
|
}
|
||||||
|
|
||||||
|
var addr sdk.Address
|
||||||
|
var secret string
|
||||||
addr, secret, err = server.GenerateSaveCoinKey(clientRoot, name, "1234567890", overwrite)
|
addr, secret, err = server.GenerateSaveCoinKey(clientRoot, name, "1234567890", overwrite)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
mm := map[string]string{"secret": secret}
|
||||||
|
var bz []byte
|
||||||
|
bz, err = cdc.MarshalJSON(mm)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cliPrint = json.RawMessage(bz)
|
||||||
|
return GaiaAppGenTxNF(cdc, pk, addr, name, overwrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a gaia genesis transaction without flags
|
||||||
|
func GaiaAppGenTxNF(cdc *wire.Codec, pk crypto.PubKey, addr sdk.Address, name string, overwrite bool) (
|
||||||
|
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||||
|
|
||||||
var bz []byte
|
var bz []byte
|
||||||
gaiaGenTx := GaiaGenTx{
|
gaiaGenTx := GaiaGenTx{
|
||||||
|
@ -111,13 +127,6 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
||||||
}
|
}
|
||||||
appGenTx = json.RawMessage(bz)
|
appGenTx = json.RawMessage(bz)
|
||||||
|
|
||||||
mm := map[string]string{"secret": secret}
|
|
||||||
bz, err = cdc.MarshalJSON(mm)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cliPrint = json.RawMessage(bz)
|
|
||||||
|
|
||||||
validator = tmtypes.GenesisValidator{
|
validator = tmtypes.GenesisValidator{
|
||||||
PubKey: pk,
|
PubKey: pk,
|
||||||
Power: freeFermionVal,
|
Power: freeFermionVal,
|
||||||
|
@ -127,7 +136,7 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
||||||
|
|
||||||
// Create the core parameters for genesis initialization for gaia
|
// Create the core parameters for genesis initialization for gaia
|
||||||
// note that the pubkey input is this machines pubkey
|
// note that the pubkey input is this machines pubkey
|
||||||
func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState GenesisState, err error) {
|
||||||
|
|
||||||
if len(appGenTxs) == 0 {
|
if len(appGenTxs) == 0 {
|
||||||
err = errors.New("must provide at least genesis transaction")
|
err = errors.New("must provide at least genesis transaction")
|
||||||
|
@ -171,10 +180,21 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the final app state
|
// create the final app state
|
||||||
genesisState := GenesisState{
|
genesisState = GenesisState{
|
||||||
Accounts: genaccs,
|
Accounts: genaccs,
|
||||||
StakeData: stakeData,
|
StakeData: stakeData,
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GaiaAppGenState but with JSON
|
||||||
|
func GaiaAppGenStateJSON(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||||
|
|
||||||
|
// create the final app state
|
||||||
|
genesisState, err := GaiaAppGenState(cdc, appGenTxs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
appState, err = wire.MarshalJSONIndent(cdc, genesisState)
|
appState, err = wire.MarshalJSONIndent(cdc, genesisState)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,46 +30,44 @@ func TestGaiaCLISend(t *testing.T) {
|
||||||
executeWrite(t, "gaiacli keys add bar", pass)
|
executeWrite(t, "gaiacli keys add bar", pass)
|
||||||
|
|
||||||
// get a free port, also setup some common flags
|
// get a free port, also setup some common flags
|
||||||
servAddr := server.FreeTCPAddr(t)
|
servAddr, port, err := server.FreeTCPAddr()
|
||||||
|
require.NoError(t, err)
|
||||||
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
|
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
|
||||||
|
|
||||||
// start gaiad server
|
// start gaiad server
|
||||||
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
||||||
defer cmd.Process.Kill()
|
defer proc.Stop(false)
|
||||||
|
tests.WaitForStart(port)
|
||||||
|
|
||||||
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
||||||
|
fooCech, err := sdk.Bech32ifyAcc(fooAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
|
barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
|
||||||
|
barCech, err := sdk.Bech32ifyAcc(barAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
fooBech, err := sdk.Bech32CosmosifyAcc(fooAddr)
|
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
barBech, err := sdk.Bech32CosmosifyAcc(barAddr)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags))
|
|
||||||
assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak"))
|
||||||
|
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barAddr), pass)
|
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
|
time.Sleep(time.Second * 2) // waiting for some blocks to pass
|
||||||
|
|
||||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barBech, flags))
|
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
|
||||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags))
|
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
|
||||||
assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak"))
|
||||||
|
|
||||||
// test autosequencing
|
// test autosequencing
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barAddr), pass)
|
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
|
time.Sleep(time.Second * 2) // waiting for some blocks to pass
|
||||||
|
|
||||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barBech, flags))
|
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
assert.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak"))
|
||||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags))
|
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
|
||||||
assert.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGaiaCLIDeclareCandidacy(t *testing.T) {
|
func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
|
|
||||||
tests.ExecuteT(t, "gaiad unsafe_reset_all")
|
tests.ExecuteT(t, "gaiad unsafe_reset_all")
|
||||||
pass := "1234567890"
|
pass := "1234567890"
|
||||||
|
@ -79,95 +77,79 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) {
|
||||||
executeWrite(t, "gaiacli keys add bar", pass)
|
executeWrite(t, "gaiacli keys add bar", pass)
|
||||||
|
|
||||||
// get a free port, also setup some common flags
|
// get a free port, also setup some common flags
|
||||||
servAddr := server.FreeTCPAddr(t)
|
servAddr, port, err := server.FreeTCPAddr()
|
||||||
|
require.NoError(t, err)
|
||||||
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
|
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
|
||||||
|
|
||||||
// start gaiad server
|
// start gaiad server
|
||||||
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
||||||
defer cmd.Process.Kill()
|
defer proc.Stop(false)
|
||||||
|
tests.WaitForStart(port)
|
||||||
|
|
||||||
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
||||||
barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
|
fooCech, err := sdk.Bech32ifyAcc(fooAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
|
||||||
|
barCech, err := sdk.Bech32ifyAcc(barAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
barCeshPubKey, err := sdk.Bech32ifyValPub(barPubKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
fooBech, err := sdk.Bech32CosmosifyAcc(fooAddr)
|
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass)
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
barBech, err := sdk.Bech32CosmosifyAcc(barAddr)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
valPrivkey := crypto.GenPrivKeyEd25519()
|
|
||||||
valAddr := sdk.Address((valPrivkey.PubKey().Address()))
|
|
||||||
bechVal, err := sdk.Bech32CosmosifyVal(valAddr)
|
|
||||||
|
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barBech), pass)
|
|
||||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||||
|
|
||||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags))
|
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak"))
|
|
||||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barBech, flags))
|
|
||||||
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
|
||||||
|
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
|
||||||
|
assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak"))
|
||||||
|
|
||||||
// declare candidacy
|
// create validator
|
||||||
declStr := fmt.Sprintf("gaiacli create-validator %v", flags)
|
cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags)
|
||||||
declStr += fmt.Sprintf(" --name=%v", "bar")
|
cvStr += fmt.Sprintf(" --name=%v", "bar")
|
||||||
declStr += fmt.Sprintf(" --validator-address=%v", bechVal)
|
cvStr += fmt.Sprintf(" --address-validator=%v", barCech)
|
||||||
declStr += fmt.Sprintf(" --amount=%v", "3steak")
|
cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey)
|
||||||
declStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
cvStr += fmt.Sprintf(" --amount=%v", "2steak")
|
||||||
fmt.Printf("debug declStr: %v\n", declStr)
|
cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
||||||
executeWrite(t, declStr, pass)
|
|
||||||
time.Sleep(time.Second) // waiting for some blocks to pass
|
executeWrite(t, cvStr, pass)
|
||||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
|
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||||
assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("steak"))
|
|
||||||
candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr))
|
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
assert.Equal(t, candidate.Owner.String(), barAddr)
|
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
|
||||||
assert.Equal(t, int64(3), candidate.PoolShares)
|
|
||||||
|
validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %v --output=json %v", barCech, flags))
|
||||||
|
assert.Equal(t, validator.Owner, barAddr)
|
||||||
|
assert.Equal(t, "2/1", validator.PoolShares.Amount.String())
|
||||||
|
|
||||||
// TODO timeout issues if not connected to the internet
|
|
||||||
// unbond a single share
|
// unbond a single share
|
||||||
//unbondStr := fmt.Sprintf("gaiacli unbond %v", flags)
|
unbondStr := fmt.Sprintf("gaiacli stake unbond %v", flags)
|
||||||
//unbondStr += fmt.Sprintf(" --name=%v", "bar")
|
unbondStr += fmt.Sprintf(" --name=%v", "bar")
|
||||||
//unbondStr += fmt.Sprintf(" --address-candidate=%v", barAddr)
|
unbondStr += fmt.Sprintf(" --address-validator=%v", barCech)
|
||||||
//unbondStr += fmt.Sprintf(" --address-delegator=%v", barAddr)
|
unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech)
|
||||||
//unbondStr += fmt.Sprintf(" --shares=%v", "1")
|
unbondStr += fmt.Sprintf(" --shares=%v", "1")
|
||||||
//unbondStr += fmt.Sprintf(" --sequence=%v", "1")
|
unbondStr += fmt.Sprintf(" --sequence=%v", "1")
|
||||||
//fmt.Printf("debug unbondStr: %v\n", unbondStr)
|
t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr))
|
||||||
//executeWrite(t, unbondStr, pass)
|
|
||||||
//time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
executeWrite(t, unbondStr, pass)
|
||||||
//barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
|
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||||
//assert.Equal(t, int64(99998), barAcc.GetCoins().AmountOf("steak"))
|
|
||||||
//candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr))
|
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
//assert.Equal(t, int64(2), candidate.BondedShares.Evaluate())
|
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
|
||||||
|
validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %v --output=json %v", barCech, flags))
|
||||||
|
assert.Equal(t, "1/1", validator.PoolShares.Amount.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//___________________________________________________________________________________
|
||||||
|
// executors
|
||||||
|
|
||||||
func executeWrite(t *testing.T, cmdStr string, writes ...string) {
|
func executeWrite(t *testing.T, cmdStr string, writes ...string) {
|
||||||
cmd, wc, _ := tests.GoExecuteT(t, cmdStr)
|
proc := tests.GoExecuteT(t, cmdStr)
|
||||||
|
|
||||||
for _, write := range writes {
|
for _, write := range writes {
|
||||||
_, err := wc.Write([]byte(write + "\n"))
|
_, err := proc.StdinPipe.Write([]byte(write + "\n"))
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
fmt.Printf("debug waiting cmdStr: %v\n", cmdStr)
|
proc.Wait()
|
||||||
cmd.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeWritePrint(t *testing.T, cmdStr string, writes ...string) {
|
|
||||||
cmd, wc, rc := tests.GoExecuteT(t, cmdStr)
|
|
||||||
|
|
||||||
for _, write := range writes {
|
|
||||||
_, err := wc.Write([]byte(write + "\n"))
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
fmt.Printf("debug waiting cmdStr: %v\n", cmdStr)
|
|
||||||
cmd.Wait()
|
|
||||||
|
|
||||||
bz := make([]byte, 100000)
|
|
||||||
rc.Read(bz)
|
|
||||||
fmt.Printf("debug read: %v\n", string(bz))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeInit(t *testing.T, cmdStr string) (chainID string) {
|
func executeInit(t *testing.T, cmdStr string) (chainID string) {
|
||||||
|
@ -187,7 +169,14 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.Address, crypto.PubKey)
|
||||||
out := tests.ExecuteT(t, cmdStr)
|
out := tests.ExecuteT(t, cmdStr)
|
||||||
var ko keys.KeyOutput
|
var ko keys.KeyOutput
|
||||||
keys.UnmarshalJSON([]byte(out), &ko)
|
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 {
|
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
||||||
|
@ -204,11 +193,11 @@ func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeGetCandidate(t *testing.T, cmdStr string) stake.Validator {
|
func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
||||||
out := tests.ExecuteT(t, cmdStr)
|
out := tests.ExecuteT(t, cmdStr)
|
||||||
var candidate stake.Validator
|
var validator stake.Validator
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
err := cdc.UnmarshalJSON([]byte(out), &candidate)
|
err := cdc.UnmarshalJSON([]byte(out), &validator)
|
||||||
require.NoError(t, err, "out %v, err %v", out, err)
|
require.NoError(t, err, "out %v\n, err %v", out, err)
|
||||||
return candidate
|
return validator
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||||
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
|
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
|
||||||
|
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
|
||||||
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
|
@ -35,36 +36,83 @@ func main() {
|
||||||
// the below functions and eliminate global vars, like we do
|
// the below functions and eliminate global vars, like we do
|
||||||
// with the cdc
|
// with the cdc
|
||||||
|
|
||||||
// add standard rpc, and tx commands
|
// add standard rpc commands
|
||||||
rpc.AddCommands(rootCmd)
|
rpc.AddCommands(rootCmd)
|
||||||
rootCmd.AddCommand(client.LineBreak)
|
|
||||||
tx.AddCommands(rootCmd, cdc)
|
|
||||||
rootCmd.AddCommand(client.LineBreak)
|
|
||||||
|
|
||||||
// add query/post commands (custom to binary)
|
//Add state commands
|
||||||
|
tendermintCmd := &cobra.Command{
|
||||||
|
Use: "tendermint",
|
||||||
|
Short: "Tendermint state querying subcommands",
|
||||||
|
}
|
||||||
|
tendermintCmd.AddCommand(
|
||||||
|
rpc.BlockCommand(),
|
||||||
|
rpc.ValidatorCommand(),
|
||||||
|
)
|
||||||
|
tx.AddCommands(tendermintCmd, cdc)
|
||||||
|
|
||||||
|
//Add IBC commands
|
||||||
|
ibcCmd := &cobra.Command{
|
||||||
|
Use: "ibc",
|
||||||
|
Short: "Inter-Blockchain Communication subcommands",
|
||||||
|
}
|
||||||
|
ibcCmd.AddCommand(
|
||||||
|
client.PostCommands(
|
||||||
|
ibccmd.IBCTransferCmd(cdc),
|
||||||
|
ibccmd.IBCRelayCmd(cdc),
|
||||||
|
)...)
|
||||||
|
|
||||||
|
advancedCmd := &cobra.Command{
|
||||||
|
Use: "advanced",
|
||||||
|
Short: "Advanced subcommands",
|
||||||
|
}
|
||||||
|
|
||||||
|
advancedCmd.AddCommand(
|
||||||
|
tendermintCmd,
|
||||||
|
ibcCmd,
|
||||||
|
lcd.ServeCommand(cdc),
|
||||||
|
)
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
|
advancedCmd,
|
||||||
|
client.LineBreak,
|
||||||
|
)
|
||||||
|
|
||||||
|
//Add stake commands
|
||||||
|
stakeCmd := &cobra.Command{
|
||||||
|
Use: "stake",
|
||||||
|
Short: "Stake and validation subcommands",
|
||||||
|
}
|
||||||
|
stakeCmd.AddCommand(
|
||||||
client.GetCommands(
|
client.GetCommands(
|
||||||
authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)),
|
|
||||||
stakecmd.GetCmdQueryValidator("stake", cdc),
|
stakecmd.GetCmdQueryValidator("stake", cdc),
|
||||||
stakecmd.GetCmdQueryValidators("stake", cdc),
|
stakecmd.GetCmdQueryValidators("stake", cdc),
|
||||||
stakecmd.GetCmdQueryDelegation("stake", cdc),
|
stakecmd.GetCmdQueryDelegation("stake", cdc),
|
||||||
stakecmd.GetCmdQueryDelegations("stake", cdc),
|
stakecmd.GetCmdQueryDelegations("stake", cdc),
|
||||||
|
slashingcmd.GetCmdQuerySigningInfo("slashing", cdc),
|
||||||
|
)...)
|
||||||
|
stakeCmd.AddCommand(
|
||||||
|
client.PostCommands(
|
||||||
|
stakecmd.GetCmdCreateValidator(cdc),
|
||||||
|
stakecmd.GetCmdEditValidator(cdc),
|
||||||
|
stakecmd.GetCmdDelegate(cdc),
|
||||||
|
stakecmd.GetCmdUnbond(cdc),
|
||||||
|
slashingcmd.GetCmdUnrevoke(cdc),
|
||||||
|
)...)
|
||||||
|
rootCmd.AddCommand(
|
||||||
|
stakeCmd,
|
||||||
|
)
|
||||||
|
|
||||||
|
//Add auth and bank commands
|
||||||
|
rootCmd.AddCommand(
|
||||||
|
client.GetCommands(
|
||||||
|
authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)),
|
||||||
)...)
|
)...)
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.PostCommands(
|
client.PostCommands(
|
||||||
bankcmd.SendTxCmd(cdc),
|
bankcmd.SendTxCmd(cdc),
|
||||||
ibccmd.IBCTransferCmd(cdc),
|
|
||||||
ibccmd.IBCRelayCmd(cdc),
|
|
||||||
stakecmd.GetCmdDeclareCandidacy(cdc),
|
|
||||||
stakecmd.GetCmdEditCandidacy(cdc),
|
|
||||||
stakecmd.GetCmdDelegate(cdc),
|
|
||||||
stakecmd.GetCmdUnbond(cdc),
|
|
||||||
)...)
|
)...)
|
||||||
|
|
||||||
// add proxy, version and key info
|
// add proxy, version and key info
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.LineBreak,
|
|
||||||
lcd.ServeCommand(cdc),
|
|
||||||
keys.Commands(),
|
keys.Commands(),
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
version.VersionCmd,
|
version.VersionCmd,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -17,6 +18,7 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
ctx := server.NewDefaultContext()
|
ctx := server.NewDefaultContext()
|
||||||
|
cobra.EnableCommandSorting = false
|
||||||
rootCmd := &cobra.Command{
|
rootCmd := &cobra.Command{
|
||||||
Use: "gaiad",
|
Use: "gaiad",
|
||||||
Short: "Gaia Daemon (server)",
|
Short: "Gaia Daemon (server)",
|
||||||
|
@ -25,7 +27,7 @@ func main() {
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
|
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
|
||||||
server.ConstructAppCreator(newApp, "gaia"),
|
server.ConstructAppCreator(newApp, "gaia"),
|
||||||
server.ConstructAppExporter(exportAppState, "gaia"))
|
server.ConstructAppExporter(exportAppStateAndTMValidators, "gaia"))
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
||||||
|
@ -36,7 +38,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
||||||
return app.NewGaiaApp(logger, db)
|
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)
|
gapp := app.NewGaiaApp(logger, db)
|
||||||
return gapp.ExportAppStateJSON()
|
return gapp.ExportAppStateAndValidators()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ swagger: '2.0'
|
||||||
info:
|
info:
|
||||||
version: '1.1.0'
|
version: '1.1.0'
|
||||||
title: Light client daemon to interface with Cosmos baseserver via REST
|
title: Light client daemon to interface with Cosmos baseserver via REST
|
||||||
description: Specification for the LCD provided by `gaiacli rest-server`
|
description: Specification for the LCD provided by `gaiacli advanced rest-server`
|
||||||
|
|
||||||
|
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
|
@ -102,7 +102,7 @@ paths:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: 12 word Seed
|
description: 16 word Seed
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
/keys/{name}:
|
/keys/{name}:
|
||||||
|
@ -204,7 +204,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: address
|
name: address
|
||||||
description: Account address
|
description: Account address in bech32 format
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
get:
|
get:
|
||||||
|
@ -222,7 +222,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: address
|
name: address
|
||||||
description: Account address
|
description: Account address in bech32 format
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
post:
|
post:
|
||||||
|
@ -255,18 +255,6 @@ paths:
|
||||||
description: Tx was send and will probably be added to the next block
|
description: Tx was send and will probably be added to the next block
|
||||||
400:
|
400:
|
||||||
description: The Tx was malformated
|
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:
|
/blocks/latest:
|
||||||
get:
|
get:
|
||||||
summary: Get the latest block
|
summary: Get the latest block
|
||||||
|
@ -304,9 +292,14 @@ paths:
|
||||||
200:
|
200:
|
||||||
description: The validator set at the latest block height
|
description: The validator set at the latest block height
|
||||||
schema:
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
block_height:
|
||||||
|
type: number
|
||||||
|
validators:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/Delegate"
|
$ref: "#/definitions/Validator"
|
||||||
/validatorsets/{height}:
|
/validatorsets/{height}:
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
|
@ -322,9 +315,14 @@ paths:
|
||||||
200:
|
200:
|
||||||
description: The validator set at a specific block height
|
description: The validator set at a specific block height
|
||||||
schema:
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
block_height:
|
||||||
|
type: number
|
||||||
|
validators:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/Delegate"
|
$ref: "#/definitions/Validator"
|
||||||
404:
|
404:
|
||||||
description: Block at height not available
|
description: Block at height not available
|
||||||
# /txs:
|
# /txs:
|
||||||
|
@ -549,7 +547,20 @@ paths:
|
||||||
definitions:
|
definitions:
|
||||||
Address:
|
Address:
|
||||||
type: string
|
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:
|
Coins:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -652,16 +663,6 @@ definitions:
|
||||||
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
||||||
Pubkey:
|
Pubkey:
|
||||||
$ref: "#/definitions/PubKey"
|
$ref: "#/definitions/PubKey"
|
||||||
PubKey:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- ed25519
|
|
||||||
data:
|
|
||||||
type: string
|
|
||||||
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
|
||||||
Account:
|
Account:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -753,17 +754,19 @@ definitions:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: object
|
type: object
|
||||||
Delegate:
|
Validator:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
address:
|
||||||
|
$ref: '#/definitions/ValidatorAddress'
|
||||||
pub_key:
|
pub_key:
|
||||||
$ref: "#/definitions/PubKey"
|
$ref: "#/definitions/ValidatorPubKey"
|
||||||
power:
|
power:
|
||||||
type: number
|
type: number
|
||||||
example: 1000
|
example: 1000
|
||||||
name:
|
accum:
|
||||||
type: string
|
type: number
|
||||||
example: "159.89.3.34"
|
example: 1000
|
||||||
# Added by API Auto Mocking Plugin
|
# Added by API Auto Mocking Plugin
|
||||||
host: virtserver.swaggerhub.com
|
host: virtserver.swaggerhub.com
|
||||||
basePath: /faboweb1/Cosmos-LCD-2/1.0.0
|
basePath: /faboweb1/Cosmos-LCD-2/1.0.0
|
||||||
|
|
|
@ -260,11 +260,11 @@ the first part will look like:
|
||||||
|
|
||||||
and you want the ``pub_key`` ``data`` that starts with ``96864CE``.
|
and you want the ``pub_key`` ``data`` that starts with ``96864CE``.
|
||||||
|
|
||||||
Now ``bob`` can declare candidacy to that pubkey:
|
Now ``bob`` can create a validator with that pubkey.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaiacli declare-candidacy --amount=10mycoin --name=bob --pubkey=<pub_key data> --moniker=bobby
|
gaiacli stake create-validator --amount=10mycoin --name=bob --address-validator=<address> --pub-key=<pubkey> --moniker=bobby
|
||||||
|
|
||||||
with an output like:
|
with an output like:
|
||||||
|
|
||||||
|
@ -306,13 +306,13 @@ First let's have ``alice`` send some coins to ``charlie``:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaiacli tx --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF
|
gaiacli send --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF
|
||||||
|
|
||||||
Then ``charlie`` will delegate some mycoin to ``bob``:
|
Then ``charlie`` will delegate some mycoin to ``bob``:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaiacli tx delegate --amount=10mycoin --name=charlie --pubkey=<pub_key data>
|
gaiacli stake delegate --amount=10mycoin --address-delegator=<charlie's address> --address-validator=<bob's address> --name=charlie
|
||||||
|
|
||||||
You'll see output like:
|
You'll see output like:
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@ To get more information about the candidate, try:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaiacli query candidate --pubkey=<pub_key data>
|
gaiacli stake validator <address>
|
||||||
|
|
||||||
and you'll see output similar to:
|
and you'll see output similar to:
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ It's also possible the query the delegator's bond like so:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaiacli query delegator-bond --delegator-address 48F74F48281C89E5E4BE9092F735EA519768E8EF --pubkey 52D6FCD8C92A97F7CCB01205ADF310A18411EA8FDCC10E65BF2FCDB05AD1689B
|
gaiacli stake delegation --address-delegator=<address> --address-validator=<address>
|
||||||
|
|
||||||
with an output similar to:
|
with an output similar to:
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ with an output similar to:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
where the ``--delegator-address`` is ``charlie``'s address and the ``-pubkey`` is the same as we've been using.
|
where the ``--address-delegator`` is ``charlie``'s address and the ``--address-validator`` is ``bob``'s address.
|
||||||
|
|
||||||
|
|
||||||
Unbonding
|
Unbonding
|
||||||
|
@ -396,7 +396,7 @@ your VotingPower reduce and your account balance increase.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaiacli unbond --amount=5mycoin --name=charlie --pubkey=<pub_key data>
|
gaiacli stake unbond --amount=5mycoin --name=charlie --address-delegator=<address> --address-validator=<address>
|
||||||
gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF
|
gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF
|
||||||
|
|
||||||
See the bond decrease with ``gaiacli query delegator-bond`` like above.
|
See the bond decrease with ``gaiacli stake delegation`` like above.
|
||||||
|
|
|
@ -44,7 +44,7 @@ Nice. We can also lookup the validator set:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaiacli validatorset
|
gaiacli advanced tendermint validator-set
|
||||||
|
|
||||||
Then, we try to transfer some ``steak`` to another account:
|
Then, we try to transfer some ``steak`` to another account:
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ Finally, to relinquish all your power, unbond some coins. You should see your Vo
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaiacli unbond --chain-id=<chain-id> --name=test
|
gaiacli stake unbond --chain-id=<chain-id> --name=test
|
||||||
|
|
||||||
That's it!
|
That's it!
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -14,6 +15,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||||
|
@ -33,6 +35,7 @@ type BasecoinApp struct {
|
||||||
keyAccount *sdk.KVStoreKey
|
keyAccount *sdk.KVStoreKey
|
||||||
keyIBC *sdk.KVStoreKey
|
keyIBC *sdk.KVStoreKey
|
||||||
keyStake *sdk.KVStoreKey
|
keyStake *sdk.KVStoreKey
|
||||||
|
keySlashing *sdk.KVStoreKey
|
||||||
|
|
||||||
// Manage getting and setting accounts
|
// Manage getting and setting accounts
|
||||||
accountMapper auth.AccountMapper
|
accountMapper auth.AccountMapper
|
||||||
|
@ -40,6 +43,7 @@ type BasecoinApp struct {
|
||||||
coinKeeper bank.Keeper
|
coinKeeper bank.Keeper
|
||||||
ibcMapper ibc.Mapper
|
ibcMapper ibc.Mapper
|
||||||
stakeKeeper stake.Keeper
|
stakeKeeper stake.Keeper
|
||||||
|
slashingKeeper slashing.Keeper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||||
|
@ -55,6 +59,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||||
keyAccount: sdk.NewKVStoreKey("acc"),
|
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||||
keyIBC: sdk.NewKVStoreKey("ibc"),
|
keyIBC: sdk.NewKVStoreKey("ibc"),
|
||||||
keyStake: sdk.NewKVStoreKey("stake"),
|
keyStake: sdk.NewKVStoreKey("stake"),
|
||||||
|
keySlashing: sdk.NewKVStoreKey("slashing"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define the accountMapper.
|
// Define the accountMapper.
|
||||||
|
@ -68,6 +73,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||||
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
||||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
|
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.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
|
// register message routes
|
||||||
app.Router().
|
app.Router().
|
||||||
|
@ -78,8 +84,10 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||||
|
|
||||||
// Initialize BaseApp.
|
// Initialize BaseApp.
|
||||||
app.SetInitChainer(app.initChainer)
|
app.SetInitChainer(app.initChainer)
|
||||||
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake)
|
app.SetBeginBlocker(app.BeginBlocker)
|
||||||
|
app.SetEndBlocker(app.EndBlocker)
|
||||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
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)
|
err := app.LoadLatestVersion(app.keyMain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmn.Exit(err.Error())
|
cmn.Exit(err.Error())
|
||||||
|
@ -94,6 +102,7 @@ func MakeCodec() *wire.Codec {
|
||||||
sdk.RegisterWire(cdc) // Register Msgs
|
sdk.RegisterWire(cdc) // Register Msgs
|
||||||
bank.RegisterWire(cdc)
|
bank.RegisterWire(cdc)
|
||||||
stake.RegisterWire(cdc)
|
stake.RegisterWire(cdc)
|
||||||
|
slashing.RegisterWire(cdc)
|
||||||
ibc.RegisterWire(cdc)
|
ibc.RegisterWire(cdc)
|
||||||
|
|
||||||
// register custom AppAccount
|
// register custom AppAccount
|
||||||
|
@ -102,6 +111,24 @@ func MakeCodec() *wire.Codec {
|
||||||
return cdc
|
return cdc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// application updates every end block
|
||||||
|
func (app *BasecoinApp) 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 *BasecoinApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||||
|
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
|
||||||
|
|
||||||
|
return abci.ResponseEndBlock{
|
||||||
|
ValidatorUpdates: validatorUpdates,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Custom logic for basecoin initialization
|
// Custom logic for basecoin initialization
|
||||||
func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||||
stateJSON := req.AppStateBytes
|
stateJSON := req.AppStateBytes
|
||||||
|
@ -121,11 +148,15 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
|
||||||
}
|
}
|
||||||
app.accountMapper.SetAccount(ctx, acc)
|
app.accountMapper.SetAccount(ctx, acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load the initial stake information
|
||||||
|
stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
|
||||||
|
|
||||||
return abci.ResponseInitChain{}
|
return abci.ResponseInitChain{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom logic for state export
|
// 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{})
|
ctx := app.NewContext(true, abci.Header{})
|
||||||
|
|
||||||
// iterate to get the accounts
|
// iterate to get the accounts
|
||||||
|
@ -143,5 +174,10 @@ func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
|
||||||
genState := types.GenesisState{
|
genState := types.GenesisState{
|
||||||
Accounts: accounts,
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,11 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
@ -85,6 +87,30 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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})
|
||||||
|
}
|
||||||
|
|
||||||
|
genesisState := types.GenesisState{
|
||||||
|
Accounts: genaccs,
|
||||||
|
StakeData: stake.DefaultGenesisState(),
|
||||||
|
}
|
||||||
|
|
||||||
|
stateBytes, err := wire.MarshalJSONIndent(bapp.cdc, genesisState)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the chain
|
||||||
|
vals := []abci.Validator{}
|
||||||
|
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||||
|
bapp.Commit()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func loggerAndDB() (log.Logger, dbm.DB) {
|
func loggerAndDB() (log.Logger, dbm.DB) {
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
|
@ -96,33 +122,11 @@ func newBasecoinApp() *BasecoinApp {
|
||||||
return NewBasecoinApp(logger, db)
|
return NewBasecoinApp(logger, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setGenesisAccounts(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})
|
|
||||||
}
|
|
||||||
|
|
||||||
genesisState := types.GenesisState{
|
|
||||||
Accounts: genaccs,
|
|
||||||
}
|
|
||||||
|
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the chain
|
|
||||||
vals := []abci.Validator{}
|
|
||||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
|
||||||
bapp.Commit()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//_______________________________________________________________________
|
//_______________________________________________________________________
|
||||||
|
|
||||||
func TestMsgs(t *testing.T) {
|
func TestMsgs(t *testing.T) {
|
||||||
bapp := newBasecoinApp()
|
bapp := newBasecoinApp()
|
||||||
|
require.Nil(t, setGenesis(bapp))
|
||||||
|
|
||||||
msgs := []struct {
|
msgs := []struct {
|
||||||
msg sdk.Msg
|
msg sdk.Msg
|
||||||
|
@ -161,7 +165,7 @@ func TestSortGenesis(t *testing.T) {
|
||||||
|
|
||||||
// Initialize the chain
|
// Initialize the chain
|
||||||
vals := []abci.Validator{}
|
vals := []abci.Validator{}
|
||||||
bapp.InitChain(abci.RequestInitChain{vals, []byte(genState)})
|
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: []byte(genState)})
|
||||||
bapp.Commit()
|
bapp.Commit()
|
||||||
|
|
||||||
// Unsorted coins means invalid
|
// Unsorted coins means invalid
|
||||||
|
@ -193,8 +197,8 @@ func TestGenesis(t *testing.T) {
|
||||||
}
|
}
|
||||||
acc := &types.AppAccount{baseAcc, "foobart"}
|
acc := &types.AppAccount{baseAcc, "foobart"}
|
||||||
|
|
||||||
err = setGenesisAccounts(bapp, baseAcc)
|
err = setGenesis(bapp, baseAcc)
|
||||||
assert.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
// A checkTx context
|
// A checkTx context
|
||||||
ctx := bapp.BaseApp.NewContext(true, abci.Header{})
|
ctx := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||||
|
@ -222,8 +226,9 @@ func TestMsgChangePubKey(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct genesis state
|
// Construct genesis state
|
||||||
err = setGenesisAccounts(bapp, baseAcc)
|
err = setGenesis(bapp, baseAcc)
|
||||||
assert.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
// A checkTx context (true)
|
// A checkTx context (true)
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||||
|
@ -276,8 +281,9 @@ func TestMsgSendWithAccounts(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct genesis state
|
// Construct genesis state
|
||||||
err = setGenesisAccounts(bapp, baseAcc)
|
err = setGenesis(bapp, baseAcc)
|
||||||
assert.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
// A checkTx context (true)
|
// A checkTx context (true)
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||||
|
@ -320,8 +326,9 @@ func TestMsgSendMultipleOut(t *testing.T) {
|
||||||
Coins: genCoins,
|
Coins: genCoins,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setGenesisAccounts(bapp, acc1, acc2)
|
// Construct genesis state
|
||||||
assert.Nil(t, err)
|
err = setGenesis(bapp, acc1, acc2)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
// Simulate a Block
|
// Simulate a Block
|
||||||
SignCheckDeliver(t, bapp, sendMsg2, []int64{0}, true, priv1)
|
SignCheckDeliver(t, bapp, sendMsg2, []int64{0}, true, priv1)
|
||||||
|
@ -353,7 +360,7 @@ func TestSengMsgMultipleInOut(t *testing.T) {
|
||||||
Coins: genCoins,
|
Coins: genCoins,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setGenesisAccounts(bapp, acc1, acc2, acc4)
|
err = setGenesis(bapp, acc1, acc2, acc4)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// CheckDeliver
|
// CheckDeliver
|
||||||
|
@ -377,7 +384,11 @@ func TestMsgSendDependent(t *testing.T) {
|
||||||
Coins: genCoins,
|
Coins: genCoins,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = setGenesisAccounts(bapp, acc1)
|
// Construct genesis state
|
||||||
|
err = setGenesis(bapp, acc1)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
err = setGenesis(bapp, acc1)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// CheckDeliver
|
// CheckDeliver
|
||||||
|
@ -416,7 +427,7 @@ func TestMsgQuiz(t *testing.T) {
|
||||||
|
|
||||||
// Initialize the chain (nil)
|
// Initialize the chain (nil)
|
||||||
vals := []abci.Validator{}
|
vals := []abci.Validator{}
|
||||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||||
bapp.Commit()
|
bapp.Commit()
|
||||||
|
|
||||||
// A checkTx context (true)
|
// A checkTx context (true)
|
||||||
|
@ -438,8 +449,9 @@ func TestIBCMsgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||||
|
|
||||||
err := setGenesisAccounts(bapp, baseAcc)
|
err := setGenesis(bapp, baseAcc)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// A checkTx context (true)
|
// A checkTx context (true)
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||||
|
|
|
@ -59,8 +59,8 @@ func main() {
|
||||||
bankcmd.SendTxCmd(cdc),
|
bankcmd.SendTxCmd(cdc),
|
||||||
ibccmd.IBCTransferCmd(cdc),
|
ibccmd.IBCTransferCmd(cdc),
|
||||||
ibccmd.IBCRelayCmd(cdc),
|
ibccmd.IBCRelayCmd(cdc),
|
||||||
stakecmd.GetCmdDeclareCandidacy(cdc),
|
stakecmd.GetCmdCreateValidator(cdc),
|
||||||
stakecmd.GetCmdEditCandidacy(cdc),
|
stakecmd.GetCmdEditValidator(cdc),
|
||||||
stakecmd.GetCmdDelegate(cdc),
|
stakecmd.GetCmdDelegate(cdc),
|
||||||
stakecmd.GetCmdUnbond(cdc),
|
stakecmd.GetCmdUnbond(cdc),
|
||||||
)...)
|
)...)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -27,7 +28,7 @@ func main() {
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
|
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
|
||||||
server.ConstructAppCreator(newApp, "basecoin"),
|
server.ConstructAppCreator(newApp, "basecoin"),
|
||||||
server.ConstructAppExporter(exportAppState, "basecoin"))
|
server.ConstructAppExporter(exportAppStateAndTMValidators, "basecoin"))
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
||||||
|
@ -39,7 +40,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
||||||
return app.NewBasecoinApp(logger, db)
|
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)
|
bapp := app.NewBasecoinApp(logger, db)
|
||||||
return bapp.ExportAppStateJSON()
|
return bapp.ExportAppStateAndValidators()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ auth.Account = (*AppAccount)(nil)
|
var _ auth.Account = (*AppAccount)(nil)
|
||||||
|
@ -42,6 +43,7 @@ func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder {
|
||||||
// State to Unmarshal
|
// State to Unmarshal
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
Accounts []*GenesisAccount `json:"accounts"`
|
Accounts []*GenesisAccount `json:"accounts"`
|
||||||
|
StakeData stake.GenesisState `json:"stake"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisAccount doesn't need pubkey or sequence
|
// GenesisAccount doesn't need pubkey or sequence
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -154,7 +155,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom logic for state export
|
// 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{})
|
ctx := app.NewContext(true, abci.Header{})
|
||||||
|
|
||||||
// iterate to get the accounts
|
// iterate to get the accounts
|
||||||
|
@ -174,5 +175,9 @@ func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
|
||||||
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
|
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
|
||||||
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ func TestGenesis(t *testing.T) {
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||||
|
|
||||||
vals := []abci.Validator{}
|
vals := []abci.Validator{}
|
||||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||||
bapp.Commit()
|
bapp.Commit()
|
||||||
|
|
||||||
// A checkTx context
|
// A checkTx context
|
||||||
|
@ -184,7 +184,7 @@ func TestMsgSendWithAccounts(t *testing.T) {
|
||||||
|
|
||||||
// Initialize the chain
|
// Initialize the chain
|
||||||
vals := []abci.Validator{}
|
vals := []abci.Validator{}
|
||||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||||
bapp.Commit()
|
bapp.Commit()
|
||||||
|
|
||||||
// A checkTx context (true)
|
// A checkTx context (true)
|
||||||
|
@ -262,7 +262,7 @@ func TestMsgMine(t *testing.T) {
|
||||||
|
|
||||||
// Initialize the chain (nil)
|
// Initialize the chain (nil)
|
||||||
vals := []abci.Validator{}
|
vals := []abci.Validator{}
|
||||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||||
bapp.Commit()
|
bapp.Commit()
|
||||||
|
|
||||||
// A checkTx context (true)
|
// A checkTx context (true)
|
||||||
|
@ -309,7 +309,7 @@ func TestMsgQuiz(t *testing.T) {
|
||||||
|
|
||||||
// Initialize the chain (nil)
|
// Initialize the chain (nil)
|
||||||
vals := []abci.Validator{}
|
vals := []abci.Validator{}
|
||||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||||
bapp.Commit()
|
bapp.Commit()
|
||||||
|
|
||||||
// A checkTx context (true)
|
// A checkTx context (true)
|
||||||
|
@ -356,7 +356,7 @@ func TestHandler(t *testing.T) {
|
||||||
}
|
}
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||||
bapp.Commit()
|
bapp.Commit()
|
||||||
|
|
||||||
// A checkTx context (true)
|
// A checkTx context (true)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -46,9 +47,9 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
||||||
return app.NewDemocoinApp(logger, db)
|
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)
|
dapp := app.NewDemocoinApp(logger, db)
|
||||||
return dapp.ExportAppStateJSON()
|
return dapp.ExportAppStateAndValidators()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -63,7 +64,7 @@ func main() {
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
||||||
server.ConstructAppCreator(newApp, "democoin"),
|
server.ConstructAppCreator(newApp, "democoin"),
|
||||||
server.ConstructAppExporter(exportAppState, "democoin"))
|
server.ConstructAppExporter(exportAppStateAndTMValidators, "democoin"))
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
rootDir := os.ExpandEnv("$HOME/.democoind")
|
rootDir := os.ExpandEnv("$HOME/.democoind")
|
||||||
|
|
|
@ -2,6 +2,7 @@ package simplestake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
@ -27,7 +28,7 @@ func handleMsgBond(ctx sdk.Context, k Keeper, msg MsgBond) sdk.Result {
|
||||||
}
|
}
|
||||||
|
|
||||||
valSet := abci.Validator{
|
valSet := abci.Validator{
|
||||||
PubKey: msg.PubKey.Bytes(),
|
PubKey: tmtypes.TM2PB.PubKey(msg.PubKey),
|
||||||
Power: power,
|
Power: power,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ func handleMsgUnbond(ctx sdk.Context, k Keeper, msg MsgUnbond) sdk.Result {
|
||||||
}
|
}
|
||||||
|
|
||||||
valSet := abci.Validator{
|
valSet := abci.Validator{
|
||||||
PubKey: pubKey.Bytes(),
|
PubKey: tmtypes.TM2PB.PubKey(pubKey),
|
||||||
Power: int64(0),
|
Power: int64(0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,9 @@ func TestKeeperGetSet(t *testing.T) {
|
||||||
cdc := wire.NewCodec()
|
cdc := wire.NewCodec()
|
||||||
auth.RegisterBaseAccount(cdc)
|
auth.RegisterBaseAccount(cdc)
|
||||||
|
|
||||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger())
|
|
||||||
accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{})
|
accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{})
|
||||||
stakeKeeper := NewKeeper(capKey, bank.NewKeeper(accountMapper), DefaultCodespace)
|
stakeKeeper := NewKeeper(capKey, bank.NewKeeper(accountMapper), DefaultCodespace)
|
||||||
|
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger())
|
||||||
addr := sdk.Address([]byte("some-address"))
|
addr := sdk.Address([]byte("some-address"))
|
||||||
|
|
||||||
bi := stakeKeeper.getBondInfo(ctx, addr)
|
bi := stakeKeeper.getBondInfo(ctx, addr)
|
||||||
|
|
|
@ -26,7 +26,7 @@ func NewMsgBond(addr sdk.Address, stake sdk.Coin, pubKey crypto.PubKey) MsgBond
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint
|
//nolint
|
||||||
func (msg MsgBond) Type() string { return moduleName } //TODO update "stake/declarecandidacy"
|
func (msg MsgBond) Type() string { return moduleName } //TODO update "stake/createvalidator"
|
||||||
func (msg MsgBond) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} }
|
func (msg MsgBond) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} }
|
||||||
|
|
||||||
// basic validation of the bond message
|
// basic validation of the bond message
|
||||||
|
@ -65,7 +65,7 @@ func NewMsgUnbond(addr sdk.Address) MsgUnbond {
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint
|
//nolint
|
||||||
func (msg MsgUnbond) Type() string { return moduleName } //TODO update "stake/declarecandidacy"
|
func (msg MsgUnbond) Type() string { return moduleName } //TODO update "stake/createvalidator"
|
||||||
func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} }
|
func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} }
|
||||||
func (msg MsgUnbond) ValidateBasic() sdk.Error { return nil }
|
func (msg MsgUnbond) ValidateBasic() sdk.Error { return nil }
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
)
|
)
|
||||||
|
@ -13,8 +14,8 @@ import (
|
||||||
// and other flags (?) to start
|
// and other flags (?) to start
|
||||||
type AppCreator func(string, log.Logger) (abci.Application, error)
|
type AppCreator func(string, log.Logger) (abci.Application, error)
|
||||||
|
|
||||||
// AppExporter dumps all app state to JSON-serializable structure
|
// 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, error)
|
type AppExporter func(home string, log log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error)
|
||||||
|
|
||||||
// ConstructAppCreator returns an application generation function
|
// ConstructAppCreator returns an application generation function
|
||||||
func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator {
|
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
|
// ConstructAppExporter returns an application export function
|
||||||
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, error), name string) AppExporter {
|
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, error) {
|
return func(rootDir string, logger log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
dataDir := filepath.Join(rootDir, "data")
|
dataDir := filepath.Join(rootDir, "data")
|
||||||
db, err := dbm.NewGoLevelDB(name, dataDir)
|
db, err := dbm.NewGoLevelDB(name, dataDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return appFn(logger, db)
|
return appFn(logger, db)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
|
||||||
Short: "Export state to JSON",
|
Short: "Export state to JSON",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
home := viper.GetString("home")
|
home := viper.GetString("home")
|
||||||
appState, err := appExporter(home, ctx.Logger)
|
appState, validators, err := appExporter(home, ctx.Logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Errorf("Error exporting state: %v\n", err)
|
return errors.Errorf("Error exporting state: %v\n", err)
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
doc.AppStateJSON = appState
|
doc.AppStateJSON = appState
|
||||||
|
doc.Validators = validators
|
||||||
encoded, err := wire.MarshalJSONIndent(cdc, doc)
|
encoded, err := wire.MarshalJSONIndent(cdc, doc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -37,7 +37,9 @@ func TestStartStandAlone(t *testing.T) {
|
||||||
|
|
||||||
app, err := mock.NewApp(home, logger)
|
app, err := mock.NewApp(home, logger)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
svr, err := server.NewServer(FreeTCPAddr(t), "socket", app)
|
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.SetLogger(logger.With("module", "abci-server"))
|
||||||
svr.Start()
|
svr.Start()
|
||||||
|
@ -69,7 +71,9 @@ func TestStartWithTendermint(t *testing.T) {
|
||||||
// set up app and start up
|
// set up app and start up
|
||||||
viper.Set(flagWithTendermint, true)
|
viper.Set(flagWithTendermint, true)
|
||||||
startCmd := StartCmd(ctx, mock.NewApp)
|
startCmd := StartCmd(ctx, mock.NewApp)
|
||||||
startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address
|
svrAddr, _, err := FreeTCPAddr()
|
||||||
|
require.NoError(t, err)
|
||||||
|
startCmd.Flags().Set(flagAddress, svrAddr) // set to a new free address
|
||||||
timeout := time.Duration(5) * time.Second
|
timeout := time.Duration(5) * time.Second
|
||||||
|
|
||||||
close(RunOrTimeout(startCmd, timeout, t))
|
close(RunOrTimeout(startCmd, timeout, t))
|
||||||
|
|
|
@ -16,14 +16,17 @@ import (
|
||||||
|
|
||||||
// Get a free address for a test tendermint server
|
// Get a free address for a test tendermint server
|
||||||
// protocol is either tcp, http, etc
|
// protocol is either tcp, http, etc
|
||||||
func FreeTCPAddr(t *testing.T) string {
|
func FreeTCPAddr() (addr, port string, err error) {
|
||||||
l, err := net.Listen("tcp", "0.0.0.0:0")
|
l, err := net.Listen("tcp", "0.0.0.0:0")
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
require.Nil(t, err)
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
port := l.Addr().(*net.TCPAddr).Port
|
portI := l.Addr().(*net.TCPAddr).Port
|
||||||
addr := fmt.Sprintf("tcp://0.0.0.0:%d", port)
|
port = fmt.Sprintf("%d", portI)
|
||||||
return addr
|
addr = fmt.Sprintf("tcp://0.0.0.0:%s", port)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupViper creates a homedir to run inside,
|
// setupViper creates a homedir to run inside,
|
||||||
|
|
|
@ -53,11 +53,11 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
|
||||||
fmt.Println(string(pubKeyJSONBytes))
|
fmt.Println(string(pubKeyJSONBytes))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
addr, err := sdk.Bech32CosmosifyValPub(valPubKey)
|
pubkey, err := sdk.Bech32ifyValPub(valPubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(addr)
|
fmt.Println(pubkey)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/version"
|
"github.com/cosmos/cosmos-sdk/version"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
|
@ -72,13 +73,24 @@ func AddCommands(
|
||||||
|
|
||||||
rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level")
|
rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level")
|
||||||
|
|
||||||
|
tendermintCmd := &cobra.Command{
|
||||||
|
Use: "tendermint",
|
||||||
|
Short: "Tendermint subcommands",
|
||||||
|
}
|
||||||
|
|
||||||
|
tendermintCmd.AddCommand(
|
||||||
|
ShowNodeIDCmd(ctx),
|
||||||
|
ShowValidatorCmd(ctx),
|
||||||
|
)
|
||||||
|
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
InitCmd(ctx, cdc, appInit),
|
InitCmd(ctx, cdc, appInit),
|
||||||
StartCmd(ctx, appCreator),
|
StartCmd(ctx, appCreator),
|
||||||
UnsafeResetAllCmd(ctx),
|
UnsafeResetAllCmd(ctx),
|
||||||
ShowNodeIDCmd(ctx),
|
client.LineBreak,
|
||||||
ShowValidatorCmd(ctx),
|
tendermintCmd,
|
||||||
ExportCmd(ctx, cdc, appExport),
|
ExportCmd(ctx, cdc, appExport),
|
||||||
|
client.LineBreak,
|
||||||
version.VersionCmd,
|
version.VersionCmd,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
104
tests/gobash.go
104
tests/gobash.go
|
@ -1,51 +1,91 @@
|
||||||
package tests
|
package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getCmd(t *testing.T, command string) *exec.Cmd {
|
// Execute the command, return stdout, logging stdout/err to t.
|
||||||
|
func ExecuteT(t *testing.T, cmd string) (out string) {
|
||||||
|
t.Log("Running", cmn.Cyan(cmd))
|
||||||
|
|
||||||
//split command into command and args
|
// Split cmd to name and args.
|
||||||
split := strings.Split(command, " ")
|
split := strings.Split(cmd, " ")
|
||||||
require.True(t, len(split) > 0, "no command provided")
|
require.True(t, len(split) > 0, "no command provided")
|
||||||
|
name, args := split[0], []string(nil)
|
||||||
var cmd *exec.Cmd
|
if len(split) > 1 {
|
||||||
if len(split) == 1 {
|
args = split[1:]
|
||||||
cmd = exec.Command(split[0])
|
|
||||||
} else {
|
|
||||||
cmd = exec.Command(split[0], split[1:]...)
|
|
||||||
}
|
}
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the command, return standard output and error, try a few times if requested
|
// Start process and wait.
|
||||||
func ExecuteT(t *testing.T, command string) (out string) {
|
proc, err := StartProcess("", name, args, nil, nil)
|
||||||
cmd := getCmd(t, command)
|
require.NoError(t, err)
|
||||||
bz, err := cmd.CombinedOutput()
|
proc.Wait()
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
// Get the output.
|
||||||
|
outbz := proc.StdoutBuffer.Bytes()
|
||||||
|
errbz := proc.StderrBuffer.Bytes()
|
||||||
|
|
||||||
|
// Log output.
|
||||||
|
if len(outbz) > 0 {
|
||||||
|
t.Log("Stdout:", cmn.Green(string(outbz)))
|
||||||
}
|
}
|
||||||
require.NoError(t, err, string(bz))
|
if len(errbz) > 0 {
|
||||||
out = strings.Trim(string(bz), "\n") //trim any new lines
|
t.Log("Stderr:", cmn.Red(string(errbz)))
|
||||||
time.Sleep(time.Second)
|
}
|
||||||
|
|
||||||
|
// Collect STDOUT output.
|
||||||
|
out = strings.Trim(string(outbz), "\n") //trim any new lines
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// Asynchronously execute the command, return standard output and error
|
// Execute the command, launch goroutines to log stdout/err to t.
|
||||||
func GoExecuteT(t *testing.T, command string) (cmd *exec.Cmd, pipeIn io.WriteCloser, pipeOut io.ReadCloser) {
|
// Caller should wait for .Wait() or .Stop() to terminate.
|
||||||
cmd = getCmd(t, command)
|
func GoExecuteT(t *testing.T, cmd string) (proc *Process) {
|
||||||
pipeIn, err := cmd.StdinPipe()
|
t.Log("Running", cmn.Cyan(cmd))
|
||||||
|
|
||||||
|
// Split cmd to name and args.
|
||||||
|
split := strings.Split(cmd, " ")
|
||||||
|
require.True(t, len(split) > 0, "no command provided")
|
||||||
|
name, args := split[0], []string(nil)
|
||||||
|
if len(split) > 1 {
|
||||||
|
args = split[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start process.
|
||||||
|
proc, err := StartProcess("", name, args, nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pipeOut, err = cmd.StdoutPipe()
|
|
||||||
require.NoError(t, err)
|
// Run goroutines to log stdout.
|
||||||
cmd.Start()
|
go func() {
|
||||||
time.Sleep(time.Second)
|
buf := make([]byte, 10240) // TODO Document the effects.
|
||||||
return cmd, pipeIn, pipeOut
|
for {
|
||||||
|
n, err := proc.StdoutBuffer.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
t.Log("Stdout:", cmn.Green(string(buf[:n])))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Run goroutines to log stderr.
|
||||||
|
go func() {
|
||||||
|
buf := make([]byte, 10240) // TODO Document the effects.
|
||||||
|
for {
|
||||||
|
n, err := proc.StderrBuffer.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
t.Log("Stderr:", cmn.Red(string(buf[:n])))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return proc
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// execution process
|
||||||
|
type Process struct {
|
||||||
|
ExecPath string
|
||||||
|
Args []string
|
||||||
|
Pid int
|
||||||
|
StartTime time.Time
|
||||||
|
EndTime time.Time
|
||||||
|
Cmd *exec.Cmd `json:"-"`
|
||||||
|
ExitState *os.ProcessState `json:"-"`
|
||||||
|
WaitCh chan struct{} `json:"-"`
|
||||||
|
StdinPipe io.WriteCloser `json:"-"`
|
||||||
|
StdoutBuffer *bytes.Buffer `json:"-"`
|
||||||
|
StderrBuffer *bytes.Buffer `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// dir: The working directory. If "", os.Getwd() is used.
|
||||||
|
// name: Command name
|
||||||
|
// args: Args to command. (should not include name)
|
||||||
|
// outFile, errFile: If not nil, will use, otherwise new Buffers will be
|
||||||
|
// allocated. Either way, Process.Cmd.StdoutPipe and Process.Cmd.StderrPipe will be nil
|
||||||
|
// respectively.
|
||||||
|
func StartProcess(dir string, name string, args []string, outFile, errFile io.WriteCloser) (*Process, error) {
|
||||||
|
var cmd = exec.Command(name, args...) // is not yet started.
|
||||||
|
// cmd dir
|
||||||
|
if dir == "" {
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
cmd.Dir = pwd
|
||||||
|
} else {
|
||||||
|
cmd.Dir = dir
|
||||||
|
}
|
||||||
|
// cmd stdin
|
||||||
|
stdin, err := cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// cmd stdout, stderr
|
||||||
|
var outBuffer, errBuffer *bytes.Buffer
|
||||||
|
if outFile != nil {
|
||||||
|
cmd.Stdout = outFile
|
||||||
|
} else {
|
||||||
|
outBuffer = bytes.NewBuffer(nil)
|
||||||
|
cmd.Stdout = outBuffer
|
||||||
|
}
|
||||||
|
if errFile != nil {
|
||||||
|
cmd.Stderr = errFile
|
||||||
|
} else {
|
||||||
|
errBuffer = bytes.NewBuffer(nil)
|
||||||
|
cmd.Stderr = errBuffer
|
||||||
|
}
|
||||||
|
// cmd start
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
proc := &Process{
|
||||||
|
ExecPath: name,
|
||||||
|
Args: args,
|
||||||
|
Pid: cmd.Process.Pid,
|
||||||
|
StartTime: time.Now(),
|
||||||
|
Cmd: cmd,
|
||||||
|
ExitState: nil,
|
||||||
|
WaitCh: make(chan struct{}),
|
||||||
|
StdinPipe: stdin,
|
||||||
|
}
|
||||||
|
if outBuffer != nil {
|
||||||
|
proc.StdoutBuffer = outBuffer
|
||||||
|
}
|
||||||
|
if errBuffer != nil {
|
||||||
|
proc.StderrBuffer = errBuffer
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
err := proc.Cmd.Wait()
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Process exit: %v\n", err)
|
||||||
|
if exitError, ok := err.(*exec.ExitError); ok {
|
||||||
|
proc.ExitState = exitError.ProcessState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proc.ExitState = proc.Cmd.ProcessState
|
||||||
|
proc.EndTime = time.Now() // TODO make this goroutine-safe
|
||||||
|
close(proc.WaitCh)
|
||||||
|
}()
|
||||||
|
return proc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop the process
|
||||||
|
func (proc *Process) Stop(kill bool) error {
|
||||||
|
if kill {
|
||||||
|
// fmt.Printf("Killing process %v\n", proc.Cmd.Process)
|
||||||
|
return proc.Cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
return proc.Cmd.Process.Signal(os.Interrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for the process
|
||||||
|
func (proc *Process) Wait() {
|
||||||
|
<-proc.WaitCh
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
//"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -239,7 +238,9 @@ func StartNodeServerForTest(t *testing.T, home string) *exec.Cmd {
|
||||||
// expects TestInitBaseCoin to have been run
|
// expects TestInitBaseCoin to have been run
|
||||||
func StartLCDServerForTest(t *testing.T, home, chainID string) (cmd *exec.Cmd, port string) {
|
func StartLCDServerForTest(t *testing.T, home, chainID string) (cmd *exec.Cmd, port string) {
|
||||||
cmdName := whereIsBasecli()
|
cmdName := whereIsBasecli()
|
||||||
port = strings.Split(server.FreeTCPAddr(t), ":")[2]
|
var err error
|
||||||
|
_, port, err = server.FreeTCPAddr()
|
||||||
|
require.NoError(t, err)
|
||||||
cmdArgs := []string{
|
cmdArgs := []string{
|
||||||
"rest-server",
|
"rest-server",
|
||||||
"--home",
|
"--home",
|
||||||
|
@ -252,7 +253,7 @@ func StartLCDServerForTest(t *testing.T, home, chainID string) (cmd *exec.Cmd, p
|
||||||
cmd = exec.Command(cmdName, cmdArgs...)
|
cmd = exec.Command(cmdName, cmdArgs...)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
err := cmd.Start()
|
err = cmd.Start()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
time.Sleep(time.Second * 2) // TODO: LOL
|
time.Sleep(time.Second * 2) // TODO: LOL
|
||||||
return cmd, port
|
return cmd, port
|
||||||
|
|
|
@ -11,16 +11,22 @@ import (
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: these functions just print to Stdout.
|
|
||||||
// consider using the logger.
|
|
||||||
|
|
||||||
// Uses localhost
|
// Uses localhost
|
||||||
func WaitForHeight(height int64, port string) {
|
func WaitForHeight(height int64, port string) {
|
||||||
for {
|
for {
|
||||||
var resultBlock ctypes.ResultBlock
|
|
||||||
|
|
||||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
|
||||||
res, err := http.Get(url)
|
|
||||||
|
// get url, try a few times
|
||||||
|
var res *http.Response
|
||||||
|
var err error
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
res, err = http.Get(url)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -31,6 +37,7 @@ func WaitForHeight(height int64, port string) {
|
||||||
}
|
}
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
|
|
||||||
|
var resultBlock ctypes.ResultBlock
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
err = cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("RES", res)
|
fmt.Println("RES", res)
|
||||||
|
@ -45,45 +52,35 @@ func WaitForHeight(height int64, port string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for 2 blocks.
|
// wait for tendermint to start
|
||||||
// uses localhost
|
|
||||||
func WaitForStart(port string) {
|
func WaitForStart(port string) {
|
||||||
waitHeight := int64(2)
|
var err error
|
||||||
for {
|
for i := 0; i < 5; i++ {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
|
||||||
res, err := http.Get(url)
|
|
||||||
if err != nil {
|
// get url, try a few times
|
||||||
panic(err)
|
var res *http.Response
|
||||||
|
res, err = http.Get(url)
|
||||||
|
if err == nil || res == nil {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// waiting for server to start ...
|
// waiting for server to start ...
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
res.Body.Close()
|
|
||||||
|
|
||||||
resultBlock := new(ctypes.ResultBlock)
|
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("RES", res)
|
|
||||||
fmt.Println("BODY", string(body))
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resultBlock.Block.Height >= waitHeight {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: these functions just print to Stdout.
|
||||||
|
// consider using the logger.
|
||||||
|
|
||||||
// Wait for the RPC server to respond to /status
|
// Wait for the RPC server to respond to /status
|
||||||
func WaitForRPC(laddr string) {
|
func WaitForRPC(laddr string) {
|
||||||
fmt.Println("LADDR", laddr)
|
fmt.Println("LADDR", laddr)
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
bech32cosmos "github.com/cosmos/bech32cosmos/go"
|
|
||||||
crypto "github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
"github.com/tendermint/tmlibs/bech32"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,24 +21,24 @@ const (
|
||||||
Bech32PrefixValPub = "cosmosvalpub"
|
Bech32PrefixValPub = "cosmosvalpub"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bech32CosmosifyAcc takes Address and returns the Bech32Cosmos encoded string
|
// Bech32ifyAcc takes Address and returns the bech32 encoded string
|
||||||
func Bech32CosmosifyAcc(addr Address) (string, error) {
|
func Bech32ifyAcc(addr Address) (string, error) {
|
||||||
return bech32cosmos.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes())
|
return bech32.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bech32CosmosifyAccPub takes AccountPubKey and returns the Bech32Cosmos encoded string
|
// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string
|
||||||
func Bech32CosmosifyAccPub(pub crypto.PubKey) (string, error) {
|
func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
|
||||||
return bech32cosmos.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
|
return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bech32CosmosifyVal returns the Bech32Cosmos encoded string for a validator address
|
// Bech32ifyVal returns the bech32 encoded string for a validator address
|
||||||
func Bech32CosmosifyVal(addr Address) (string, error) {
|
func Bech32ifyVal(addr Address) (string, error) {
|
||||||
return bech32cosmos.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes())
|
return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bech32CosmosifyValPub returns the Bech32Cosmos encoded string for a validator pubkey
|
// Bech32ifyValPub returns the bech32 encoded string for a validator pubkey
|
||||||
func Bech32CosmosifyValPub(pub crypto.PubKey) (string, error) {
|
func Bech32ifyValPub(pub crypto.PubKey) (string, error) {
|
||||||
return bech32cosmos.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
|
return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an Address from a string
|
// create an Address from a string
|
||||||
|
@ -54,14 +54,29 @@ func GetAccAddressHex(address string) (addr Address, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an Address from a string
|
// create an Address from a string
|
||||||
func GetAccAddressBech32Cosmos(address string) (addr Address, err error) {
|
func GetAccAddressBech32(address string) (addr Address, err error) {
|
||||||
bz, err := getFromBech32Cosmos(address, Bech32PrefixAccAddr)
|
bz, err := getFromBech32(address, Bech32PrefixAccAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return Address(bz), nil
|
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
|
// create an Address from a hex string
|
||||||
func GetValAddressHex(address string) (addr Address, err error) {
|
func GetValAddressHex(address string) (addr Address, err error) {
|
||||||
if len(address) == 0 {
|
if len(address) == 0 {
|
||||||
|
@ -74,9 +89,9 @@ func GetValAddressHex(address string) (addr Address, err error) {
|
||||||
return Address(bz), nil
|
return Address(bz), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an Address from a bech32cosmos string
|
// create an Address from a bech32 string
|
||||||
func GetValAddressBech32Cosmos(address string) (addr Address, err error) {
|
func GetValAddressBech32(address string) (addr Address, err error) {
|
||||||
bz, err := getFromBech32Cosmos(address, Bech32PrefixValAddr)
|
bz, err := getFromBech32(address, Bech32PrefixValAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -84,8 +99,8 @@ func GetValAddressBech32Cosmos(address string) (addr Address, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Decode a validator publickey into a public key
|
//Decode a validator publickey into a public key
|
||||||
func GetValPubKeyBech32Cosmos(pubkey string) (pk crypto.PubKey, err error) {
|
func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
|
||||||
bz, err := getFromBech32Cosmos(pubkey, Bech32PrefixValPub)
|
bz, err := getFromBech32(pubkey, Bech32PrefixValPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -98,11 +113,11 @@ func GetValPubKeyBech32Cosmos(pubkey string) (pk crypto.PubKey, err error) {
|
||||||
return pk, nil
|
return pk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFromBech32Cosmos(bech32, prefix string) ([]byte, error) {
|
func getFromBech32(bech32str, prefix string) ([]byte, error) {
|
||||||
if len(bech32) == 0 {
|
if len(bech32str) == 0 {
|
||||||
return nil, errors.New("must provide non-empty string")
|
return nil, errors.New("must provide non-empty string")
|
||||||
}
|
}
|
||||||
hrp, bz, err := bech32cosmos.DecodeAndConvert(bech32)
|
hrp, bz, err := bech32.DecodeAndConvert(bech32str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ type Context struct {
|
||||||
|
|
||||||
// create a new context
|
// create a new context
|
||||||
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byte, logger log.Logger) Context {
|
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byte, logger log.Logger) Context {
|
||||||
|
|
||||||
c := Context{
|
c := Context{
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
pst: newThePast(),
|
pst: newThePast(),
|
||||||
|
@ -43,6 +44,7 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byt
|
||||||
c = c.WithIsCheckTx(isCheckTx)
|
c = c.WithIsCheckTx(isCheckTx)
|
||||||
c = c.WithTxBytes(txBytes)
|
c = c.WithTxBytes(txBytes)
|
||||||
c = c.WithLogger(logger)
|
c = c.WithLogger(logger)
|
||||||
|
c = c.WithSigningValidators(nil)
|
||||||
c = c.WithGasMeter(NewInfiniteGasMeter())
|
c = c.WithGasMeter(NewInfiniteGasMeter())
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -128,6 +130,7 @@ const (
|
||||||
contextKeyIsCheckTx
|
contextKeyIsCheckTx
|
||||||
contextKeyTxBytes
|
contextKeyTxBytes
|
||||||
contextKeyLogger
|
contextKeyLogger
|
||||||
|
contextKeySigningValidators
|
||||||
contextKeyGasMeter
|
contextKeyGasMeter
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -157,6 +160,9 @@ func (c Context) TxBytes() []byte {
|
||||||
func (c Context) Logger() log.Logger {
|
func (c Context) Logger() log.Logger {
|
||||||
return c.Value(contextKeyLogger).(log.Logger)
|
return c.Value(contextKeyLogger).(log.Logger)
|
||||||
}
|
}
|
||||||
|
func (c Context) SigningValidators() []abci.SigningValidator {
|
||||||
|
return c.Value(contextKeySigningValidators).([]abci.SigningValidator)
|
||||||
|
}
|
||||||
func (c Context) GasMeter() GasMeter {
|
func (c Context) GasMeter() GasMeter {
|
||||||
return c.Value(contextKeyGasMeter).(GasMeter)
|
return c.Value(contextKeyGasMeter).(GasMeter)
|
||||||
}
|
}
|
||||||
|
@ -182,6 +188,9 @@ func (c Context) WithTxBytes(txBytes []byte) Context {
|
||||||
func (c Context) WithLogger(logger log.Logger) Context {
|
func (c Context) WithLogger(logger log.Logger) Context {
|
||||||
return c.withValue(contextKeyLogger, logger)
|
return c.withValue(contextKeyLogger, logger)
|
||||||
}
|
}
|
||||||
|
func (c Context) WithSigningValidators(SigningValidators []abci.SigningValidator) Context {
|
||||||
|
return c.withValue(contextKeySigningValidators, SigningValidators)
|
||||||
|
}
|
||||||
func (c Context) WithGasMeter(meter GasMeter) Context {
|
func (c Context) WithGasMeter(meter GasMeter) Context {
|
||||||
return c.withValue(contextKeyGasMeter, meter)
|
return c.withValue(contextKeyGasMeter, meter)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package types
|
||||||
import (
|
import (
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
"github.com/tendermint/go-crypto"
|
"github.com/tendermint/go-crypto"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// status of a validator
|
// status of a validator
|
||||||
|
@ -31,6 +32,7 @@ func BondStatusToString(b BondStatus) string {
|
||||||
|
|
||||||
// validator for a delegated proof of stake system
|
// validator for a delegated proof of stake system
|
||||||
type Validator interface {
|
type Validator interface {
|
||||||
|
GetMoniker() string // moniker of the validator
|
||||||
GetStatus() BondStatus // status of the validator
|
GetStatus() BondStatus // status of the validator
|
||||||
GetOwner() Address // owner address to receive/return validators coins
|
GetOwner() Address // owner address to receive/return validators coins
|
||||||
GetPubKey() crypto.PubKey // validation pubkey
|
GetPubKey() crypto.PubKey // validation pubkey
|
||||||
|
@ -41,7 +43,7 @@ type Validator interface {
|
||||||
// validator which fulfills abci validator interface for use in Tendermint
|
// validator which fulfills abci validator interface for use in Tendermint
|
||||||
func ABCIValidator(v Validator) abci.Validator {
|
func ABCIValidator(v Validator) abci.Validator {
|
||||||
return abci.Validator{
|
return abci.Validator{
|
||||||
PubKey: v.GetPubKey().Bytes(),
|
PubKey: tmtypes.TM2PB.PubKey(v.GetPubKey()),
|
||||||
Power: v.GetPower().Evaluate(),
|
Power: v.GetPower().Evaluate(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +60,9 @@ type ValidatorSet interface {
|
||||||
|
|
||||||
Validator(Context, Address) Validator // get a particular validator by owner address
|
Validator(Context, Address) Validator // get a particular validator by owner address
|
||||||
TotalPower(Context) Rat // total power of the validator set
|
TotalPower(Context) Rat // total power of the validator set
|
||||||
|
Slash(Context, crypto.PubKey, int64, Rat) // slash the validator and delegators of the validator, specifying offence height & slash fraction
|
||||||
|
Revoke(Context, crypto.PubKey) // revoke a validator
|
||||||
|
Unrevoke(Context, crypto.PubKey) // unrevoke a validator
|
||||||
}
|
}
|
||||||
|
|
||||||
//_______________________________________________________________________________
|
//_______________________________________________________________________________
|
||||||
|
|
|
@ -25,6 +25,11 @@ func (t Tags) AppendTags(a Tags) Tags {
|
||||||
return append(t, a...)
|
return append(t, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Turn tags into KVPair list
|
||||||
|
func (t Tags) ToKVPairs() []cmn.KVPair {
|
||||||
|
return []cmn.KVPair(t)
|
||||||
|
}
|
||||||
|
|
||||||
// New variadic tags, must be k string, v []byte repeating
|
// New variadic tags, must be k string, v []byte repeating
|
||||||
func NewTags(tags ...interface{}) Tags {
|
func NewTags(tags ...interface{}) Tags {
|
||||||
var ret Tags
|
var ret Tags
|
||||||
|
|
|
@ -35,7 +35,7 @@ type Tx interface {
|
||||||
|
|
||||||
//__________________________________________________________
|
//__________________________________________________________
|
||||||
|
|
||||||
// TxDeocder unmarshals transaction bytes
|
// TxDecoder unmarshals transaction bytes
|
||||||
type TxDecoder func(txBytes []byte) (Tx, Error)
|
type TxDecoder func(txBytes []byte) (Tx, Error)
|
||||||
|
|
||||||
//__________________________________________________________
|
//__________________________________________________________
|
||||||
|
|
|
@ -40,7 +40,7 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode
|
||||||
// find the key to look up the account
|
// find the key to look up the account
|
||||||
addr := args[0]
|
addr := args[0]
|
||||||
|
|
||||||
key, err := sdk.GetAccAddressBech32Cosmos(addr)
|
key, err := sdk.GetAccAddressBech32(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package rest
|
package rest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
@ -26,17 +25,16 @@ func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, sto
|
||||||
func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc {
|
func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
addr := vars["address"]
|
bech32addr := vars["address"]
|
||||||
|
|
||||||
bz, err := hex.DecodeString(addr)
|
addr, err := sdk.GetAccAddressBech32(bech32addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
key := sdk.Address(bz)
|
|
||||||
|
|
||||||
res, err := ctx.Query(key, storeName)
|
res, err := ctx.Query(addr, storeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error())))
|
w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error())))
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
)
|
)
|
||||||
|
@ -30,7 +28,7 @@ func (msg MsgChangeKey) ValidateBasic() sdk.Error {
|
||||||
|
|
||||||
// Implements Msg.
|
// Implements Msg.
|
||||||
func (msg MsgChangeKey) GetSignBytes() []byte {
|
func (msg MsgChangeKey) GetSignBytes() []byte {
|
||||||
b, err := json.Marshal(msg) // XXX: ensure some canonical form
|
b, err := msgCdc.MarshalJSON(msg) // XXX: ensure some canonical form
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
)
|
)
|
||||||
|
@ -70,7 +68,7 @@ func (fee StdFee) Bytes() []byte {
|
||||||
if len(fee.Amount) == 0 {
|
if len(fee.Amount) == 0 {
|
||||||
fee.Amount = sdk.Coins{}
|
fee.Amount = sdk.Coins{}
|
||||||
}
|
}
|
||||||
bz, err := json.Marshal(fee) // TODO
|
bz, err := msgCdc.MarshalJSON(fee) // TODO
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -95,7 +93,7 @@ type StdSignDoc struct {
|
||||||
// StdSignBytes returns the bytes to sign for a transaction.
|
// StdSignBytes returns the bytes to sign for a transaction.
|
||||||
// TODO: change the API to just take a chainID and StdTx ?
|
// TODO: change the API to just take a chainID and StdTx ?
|
||||||
func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg sdk.Msg) []byte {
|
func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg sdk.Msg) []byte {
|
||||||
bz, err := json.Marshal(StdSignDoc{
|
bz, err := msgCdc.MarshalJSON(StdSignDoc{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
Sequences: sequences,
|
Sequences: sequences,
|
||||||
FeeBytes: fee.Bytes(),
|
FeeBytes: fee.Bytes(),
|
||||||
|
|
|
@ -10,3 +10,10 @@ func RegisterWire(cdc *wire.Codec) {
|
||||||
cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil)
|
cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", nil)
|
||||||
cdc.RegisterConcrete(MsgChangeKey{}, "auth/ChangeKey", nil)
|
cdc.RegisterConcrete(MsgChangeKey{}, "auth/ChangeKey", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msgCdc = wire.NewCodec()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterWire(msgCdc)
|
||||||
|
wire.RegisterCrypto(msgCdc)
|
||||||
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||||
|
|
||||||
toStr := viper.GetString(flagTo)
|
toStr := viper.GetString(flagTo)
|
||||||
|
|
||||||
to, err := sdk.GetAccAddressBech32Cosmos(toStr)
|
to, err := sdk.GetAccAddressBech32(toStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank/client"
|
"github.com/cosmos/cosmos-sdk/x/bank/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,12 +30,25 @@ type sendBody struct {
|
||||||
Sequence int64 `json:"sequence"`
|
Sequence int64 `json:"sequence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msgCdc = wire.NewCodec()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
bank.RegisterWire(msgCdc)
|
||||||
|
}
|
||||||
|
|
||||||
// SendRequestHandlerFn - http request handler to send coins to a address
|
// SendRequestHandlerFn - http request handler to send coins to a address
|
||||||
func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
|
func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
// collect data
|
// collect data
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
address := vars["address"]
|
bech32addr := vars["address"]
|
||||||
|
|
||||||
|
address, err := sdk.GetAccAddressBech32(bech32addr)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var m sendBody
|
var m sendBody
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
@ -43,7 +57,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(body, &m)
|
err = msgCdc.UnmarshalJSON(body, &m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
|
@ -57,7 +71,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
to, err := sdk.GetAccAddressHex(address)
|
to, err := sdk.GetAccAddressHex(address.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package bank
|
package bank
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -55,7 +53,7 @@ func (msg MsgSend) ValidateBasic() sdk.Error {
|
||||||
|
|
||||||
// Implements Msg.
|
// Implements Msg.
|
||||||
func (msg MsgSend) GetSignBytes() []byte {
|
func (msg MsgSend) GetSignBytes() []byte {
|
||||||
b, err := json.Marshal(msg) // XXX: ensure some canonical form
|
b, err := msgCdc.MarshalJSON(msg) // XXX: ensure some canonical form
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -104,7 +102,7 @@ func (msg MsgIssue) ValidateBasic() sdk.Error {
|
||||||
|
|
||||||
// Implements Msg.
|
// Implements Msg.
|
||||||
func (msg MsgIssue) GetSignBytes() []byte {
|
func (msg MsgIssue) GetSignBytes() []byte {
|
||||||
b, err := json.Marshal(msg) // XXX: ensure some canonical form
|
b, err := msgCdc.MarshalJSON(msg) // XXX: ensure some canonical form
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,8 +186,14 @@ func TestMsgSendGetSignBytes(t *testing.T) {
|
||||||
Outputs: []Output{NewOutput(addr2, coins)},
|
Outputs: []Output{NewOutput(addr2, coins)},
|
||||||
}
|
}
|
||||||
res := msg.GetSignBytes()
|
res := msg.GetSignBytes()
|
||||||
|
|
||||||
|
unmarshaledMsg := &MsgSend{}
|
||||||
|
msgCdc.UnmarshalJSON(res, unmarshaledMsg)
|
||||||
|
assert.Equal(t, &msg, unmarshaledMsg)
|
||||||
|
|
||||||
// TODO bad results
|
// TODO bad results
|
||||||
assert.Equal(t, string(res), `{"inputs":[{"address":"696E707574","coins":[{"denom":"atom","amount":10}]}],"outputs":[{"address":"6F7574707574","coins":[{"denom":"atom","amount":10}]}]}`)
|
expected := `{"type":"EAFDE32A2C87F8","value":{"inputs":[{"address":"696E707574","coins":[{"denom":"atom","amount":10}]}],"outputs":[{"address":"6F7574707574","coins":[{"denom":"atom","amount":10}]}]}}`
|
||||||
|
assert.Equal(t, expected, string(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMsgSendGetSigners(t *testing.T) {
|
func TestMsgSendGetSigners(t *testing.T) {
|
||||||
|
@ -255,8 +261,14 @@ func TestMsgIssueGetSignBytes(t *testing.T) {
|
||||||
Outputs: []Output{NewOutput(addr, coins)},
|
Outputs: []Output{NewOutput(addr, coins)},
|
||||||
}
|
}
|
||||||
res := msg.GetSignBytes()
|
res := msg.GetSignBytes()
|
||||||
|
|
||||||
|
unmarshaledMsg := &MsgIssue{}
|
||||||
|
msgCdc.UnmarshalJSON(res, unmarshaledMsg)
|
||||||
|
assert.Equal(t, &msg, unmarshaledMsg)
|
||||||
|
|
||||||
// TODO bad results
|
// TODO bad results
|
||||||
assert.Equal(t, string(res), `{"banker":"696E707574","outputs":[{"address":"6C6F616E2D66726F6D2D62616E6B","coins":[{"denom":"atom","amount":10}]}]}`)
|
expected := `{"type":"72E617C06ABAD0","value":{"banker":"696E707574","outputs":[{"address":"6C6F616E2D66726F6D2D62616E6B","coins":[{"denom":"atom","amount":10}]}]}}`
|
||||||
|
assert.Equal(t, expected, string(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMsgIssueGetSigners(t *testing.T) {
|
func TestMsgIssueGetSigners(t *testing.T) {
|
||||||
|
|
|
@ -9,3 +9,9 @@ func RegisterWire(cdc *wire.Codec) {
|
||||||
cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/Send", nil)
|
cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/Send", nil)
|
||||||
cdc.RegisterConcrete(MsgIssue{}, "cosmos-sdk/Issue", nil)
|
cdc.RegisterConcrete(MsgIssue{}, "cosmos-sdk/Issue", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var msgCdc = wire.NewCodec()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterWire(msgCdc)
|
||||||
|
}
|
||||||
|
|
|
@ -35,7 +35,14 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
|
||||||
// collect data
|
// collect data
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
destChainID := vars["destchain"]
|
destChainID := vars["destchain"]
|
||||||
address := vars["address"]
|
bech32addr := vars["address"]
|
||||||
|
|
||||||
|
address, err := sdk.GetAccAddressBech32(bech32addr)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var m transferBody
|
var m transferBody
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
@ -58,7 +65,7 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bz, err := hex.DecodeString(address)
|
bz, err := hex.DecodeString(address.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
const (
|
||||||
|
FlagAddressValidator = "address-validator"
|
||||||
|
)
|
|
@ -0,0 +1,57 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/tendermint/tmlibs/cli"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire" // XXX fix
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// get the command to query signing info
|
||||||
|
func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "signing-info [validator-pubkey]",
|
||||||
|
Short: "Query a validator's signing information",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
|
pk, err := sdk.GetValPubKeyBech32(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key := slashing.GetValidatorSigningInfoKey(pk.Address())
|
||||||
|
ctx := context.NewCoreContextFromViper()
|
||||||
|
res, err := ctx.Query(key, storeName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
signingInfo := new(slashing.ValidatorSigningInfo)
|
||||||
|
cdc.MustUnmarshalBinary(res, signingInfo)
|
||||||
|
|
||||||
|
switch viper.Get(cli.OutputFlag) {
|
||||||
|
|
||||||
|
case "text":
|
||||||
|
human := signingInfo.HumanReadableString()
|
||||||
|
fmt.Println(human)
|
||||||
|
|
||||||
|
case "json":
|
||||||
|
// parse out the signing info
|
||||||
|
output, err := wire.MarshalJSONIndent(cdc, signingInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(string(output))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// create unrevoke command
|
||||||
|
func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "unrevoke",
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
Short: "unrevoke validator previously revoked for downtime",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
||||||
|
|
||||||
|
validatorAddr, err := sdk.GetAccAddressBech32(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := slashing.NewMsgUnrevoke(validatorAddr)
|
||||||
|
|
||||||
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, msg, cdc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
//nolint
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Local code type
|
||||||
|
type CodeType = sdk.CodeType
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Default slashing codespace
|
||||||
|
DefaultCodespace sdk.CodespaceType = 10
|
||||||
|
|
||||||
|
// Invalid validator
|
||||||
|
CodeInvalidValidator CodeType = 201
|
||||||
|
// Validator jailed
|
||||||
|
CodeValidatorJailed CodeType = 202
|
||||||
|
)
|
||||||
|
|
||||||
|
func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error {
|
||||||
|
return newError(codespace, CodeInvalidValidator, "That address is not associated with any known validator")
|
||||||
|
}
|
||||||
|
func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||||
|
return newError(codespace, CodeInvalidValidator, "Validator does not exist for that address")
|
||||||
|
}
|
||||||
|
func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error {
|
||||||
|
return newError(codespace, CodeValidatorJailed, "Validator jailed, cannot yet be unrevoked")
|
||||||
|
}
|
||||||
|
|
||||||
|
func codeToDefaultMsg(code CodeType) string {
|
||||||
|
switch code {
|
||||||
|
case CodeInvalidValidator:
|
||||||
|
return "Invalid Validator"
|
||||||
|
case CodeValidatorJailed:
|
||||||
|
return "Validator Jailed"
|
||||||
|
default:
|
||||||
|
return sdk.CodeToDefaultMsg(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func msgOrDefaultMsg(msg string, code CodeType) string {
|
||||||
|
if msg != "" {
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
return codeToDefaultMsg(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newError(codespace sdk.CodespaceType, code CodeType, msg string) sdk.Error {
|
||||||
|
msg = msgOrDefaultMsg(msg, code)
|
||||||
|
return sdk.NewError(codespace, code, msg)
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewHandler(k Keeper) sdk.Handler {
|
||||||
|
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
|
// NOTE msg already has validate basic run
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case MsgUnrevoke:
|
||||||
|
return handleMsgUnrevoke(ctx, msg, k)
|
||||||
|
default:
|
||||||
|
return sdk.ErrTxDecode("invalid message parse in staking module").Result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validators must submit a transaction to unrevoke itself after
|
||||||
|
// having been revoked (and thus unbonded) for downtime
|
||||||
|
func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result {
|
||||||
|
|
||||||
|
// Validator must exist
|
||||||
|
validator := k.validatorSet.Validator(ctx, msg.ValidatorAddr)
|
||||||
|
if validator == nil {
|
||||||
|
return ErrNoValidatorForAddress(k.codespace).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := validator.GetPubKey().Address()
|
||||||
|
|
||||||
|
// Signing info must exist
|
||||||
|
info, found := k.getValidatorSigningInfo(ctx, addr)
|
||||||
|
if !found {
|
||||||
|
return ErrNoValidatorForAddress(k.codespace).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot be unrevoked until out of jail
|
||||||
|
if ctx.BlockHeader().Time < info.JailedUntil {
|
||||||
|
return ErrValidatorJailed(k.codespace).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.IsCheckTx() {
|
||||||
|
return sdk.Result{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the starting height (so the validator can't be immediately revoked again)
|
||||||
|
info.StartHeight = ctx.BlockHeight()
|
||||||
|
k.setValidatorSigningInfo(ctx, addr, info)
|
||||||
|
|
||||||
|
// Unrevoke the validator
|
||||||
|
k.validatorSet.Unrevoke(ctx, validator.GetPubKey())
|
||||||
|
|
||||||
|
tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes())
|
||||||
|
|
||||||
|
return sdk.Result{
|
||||||
|
Tags: tags,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keeper of the slashing store
|
||||||
|
type Keeper struct {
|
||||||
|
storeKey sdk.StoreKey
|
||||||
|
cdc *wire.Codec
|
||||||
|
validatorSet sdk.ValidatorSet
|
||||||
|
|
||||||
|
// codespace
|
||||||
|
codespace sdk.CodespaceType
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewKeeper creates a slashing keeper
|
||||||
|
func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, codespace sdk.CodespaceType) Keeper {
|
||||||
|
keeper := Keeper{
|
||||||
|
storeKey: key,
|
||||||
|
cdc: cdc,
|
||||||
|
validatorSet: vs,
|
||||||
|
codespace: codespace,
|
||||||
|
}
|
||||||
|
return keeper
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle a validator signing two blocks at the same height
|
||||||
|
func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64, pubkey crypto.PubKey) {
|
||||||
|
logger := ctx.Logger().With("module", "x/slashing")
|
||||||
|
age := ctx.BlockHeader().Time - timestamp
|
||||||
|
|
||||||
|
// Double sign too old
|
||||||
|
if age > MaxEvidenceAge {
|
||||||
|
logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), height, age, MaxEvidenceAge))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double sign confirmed
|
||||||
|
logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge))
|
||||||
|
k.validatorSet.Slash(ctx, pubkey, height, SlashFractionDoubleSign)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle a validator signature, must be called once per validator per block
|
||||||
|
func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, signed bool) {
|
||||||
|
logger := ctx.Logger().With("module", "x/slashing")
|
||||||
|
height := ctx.BlockHeight()
|
||||||
|
if !signed {
|
||||||
|
logger.Info(fmt.Sprintf("Absent validator %s at height %d", pubkey.Address(), height))
|
||||||
|
}
|
||||||
|
address := pubkey.Address()
|
||||||
|
|
||||||
|
// Local index, so counts blocks validator *should* have signed
|
||||||
|
// Will use the 0-value default signing info if not present
|
||||||
|
signInfo, _ := k.getValidatorSigningInfo(ctx, address)
|
||||||
|
index := signInfo.IndexOffset % SignedBlocksWindow
|
||||||
|
signInfo.IndexOffset++
|
||||||
|
|
||||||
|
// Update signed block bit array & counter
|
||||||
|
// This counter just tracks the sum of the bit array
|
||||||
|
// That way we avoid needing to read/write the whole array each time
|
||||||
|
previous := k.getValidatorSigningBitArray(ctx, address, index)
|
||||||
|
if previous == signed {
|
||||||
|
// Array value at this index has not changed, no need to update counter
|
||||||
|
} else if previous && !signed {
|
||||||
|
// Array value has changed from signed to unsigned, decrement counter
|
||||||
|
k.setValidatorSigningBitArray(ctx, address, index, false)
|
||||||
|
signInfo.SignedBlocksCounter--
|
||||||
|
} else if !previous && signed {
|
||||||
|
// Array value has changed from unsigned to signed, increment counter
|
||||||
|
k.setValidatorSigningBitArray(ctx, address, index, true)
|
||||||
|
signInfo.SignedBlocksCounter++
|
||||||
|
}
|
||||||
|
|
||||||
|
minHeight := signInfo.StartHeight + SignedBlocksWindow
|
||||||
|
if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow {
|
||||||
|
// Downtime confirmed, slash, revoke, and jail the validator
|
||||||
|
logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow))
|
||||||
|
k.validatorSet.Slash(ctx, pubkey, height, SlashFractionDowntime)
|
||||||
|
k.validatorSet.Revoke(ctx, pubkey)
|
||||||
|
signInfo.JailedUntil = ctx.BlockHeader().Time + DowntimeUnbondDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the updated signing info
|
||||||
|
k.setValidatorSigningInfo(ctx, address, signInfo)
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHandleDoubleSign(t *testing.T) {
|
||||||
|
|
||||||
|
// initial setup
|
||||||
|
ctx, ck, sk, keeper := createTestInput(t)
|
||||||
|
addr, val, amt := addrs[0], pks[0], int64(100)
|
||||||
|
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||||
|
require.True(t, got.IsOK())
|
||||||
|
stake.EndBlocker(ctx, sk)
|
||||||
|
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}})
|
||||||
|
require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower())
|
||||||
|
|
||||||
|
// double sign less than max age
|
||||||
|
keeper.handleDoubleSign(ctx, 0, 0, val)
|
||||||
|
require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower())
|
||||||
|
ctx = ctx.WithBlockHeader(abci.Header{Time: 300})
|
||||||
|
|
||||||
|
// double sign past max age
|
||||||
|
keeper.handleDoubleSign(ctx, 0, 0, val)
|
||||||
|
require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleAbsentValidator(t *testing.T) {
|
||||||
|
|
||||||
|
// initial setup
|
||||||
|
ctx, ck, sk, keeper := createTestInput(t)
|
||||||
|
addr, val, amt := addrs[0], pks[0], int64(100)
|
||||||
|
sh := stake.NewHandler(sk)
|
||||||
|
slh := NewHandler(keeper)
|
||||||
|
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
|
||||||
|
require.True(t, got.IsOK())
|
||||||
|
stake.EndBlocker(ctx, sk)
|
||||||
|
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}})
|
||||||
|
require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower())
|
||||||
|
info, found := keeper.getValidatorSigningInfo(ctx, val.Address())
|
||||||
|
require.False(t, found)
|
||||||
|
require.Equal(t, int64(0), info.StartHeight)
|
||||||
|
require.Equal(t, int64(0), info.IndexOffset)
|
||||||
|
require.Equal(t, int64(0), info.SignedBlocksCounter)
|
||||||
|
require.Equal(t, int64(0), info.JailedUntil)
|
||||||
|
height := int64(0)
|
||||||
|
|
||||||
|
// 1000 first blocks OK
|
||||||
|
for ; height < 1000; height++ {
|
||||||
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
keeper.handleValidatorSignature(ctx, val, true)
|
||||||
|
}
|
||||||
|
info, found = keeper.getValidatorSigningInfo(ctx, val.Address())
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, int64(0), info.StartHeight)
|
||||||
|
require.Equal(t, SignedBlocksWindow, info.SignedBlocksCounter)
|
||||||
|
|
||||||
|
// 50 blocks missed
|
||||||
|
for ; height < 1050; height++ {
|
||||||
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
keeper.handleValidatorSignature(ctx, val, false)
|
||||||
|
}
|
||||||
|
info, found = keeper.getValidatorSigningInfo(ctx, val.Address())
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, int64(0), info.StartHeight)
|
||||||
|
require.Equal(t, SignedBlocksWindow-50, info.SignedBlocksCounter)
|
||||||
|
|
||||||
|
// validator should be bonded still
|
||||||
|
validator, _ := sk.GetValidatorByPubKey(ctx, val)
|
||||||
|
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||||
|
pool := sk.GetPool(ctx)
|
||||||
|
require.Equal(t, int64(100), pool.BondedTokens)
|
||||||
|
|
||||||
|
// 51st block missed
|
||||||
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
keeper.handleValidatorSignature(ctx, val, false)
|
||||||
|
info, found = keeper.getValidatorSigningInfo(ctx, val.Address())
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, int64(0), info.StartHeight)
|
||||||
|
require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter)
|
||||||
|
|
||||||
|
// validator should have been revoked
|
||||||
|
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||||
|
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
||||||
|
|
||||||
|
// unrevocation should fail prior to jail expiration
|
||||||
|
got = slh(ctx, NewMsgUnrevoke(addr))
|
||||||
|
require.False(t, got.IsOK())
|
||||||
|
|
||||||
|
// unrevocation should succeed after jail expiration
|
||||||
|
ctx = ctx.WithBlockHeader(abci.Header{Time: int64(86400 * 2)})
|
||||||
|
got = slh(ctx, NewMsgUnrevoke(addr))
|
||||||
|
require.True(t, got.IsOK())
|
||||||
|
|
||||||
|
// validator should be rebonded now
|
||||||
|
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||||
|
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||||
|
|
||||||
|
// validator should have been slashed
|
||||||
|
pool = sk.GetPool(ctx)
|
||||||
|
require.Equal(t, int64(99), pool.BondedTokens)
|
||||||
|
|
||||||
|
// validator start height should have been changed
|
||||||
|
info, found = keeper.getValidatorSigningInfo(ctx, val.Address())
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, height, info.StartHeight)
|
||||||
|
require.Equal(t, SignedBlocksWindow-51, info.SignedBlocksCounter)
|
||||||
|
|
||||||
|
// validator should not be immediately revoked again
|
||||||
|
height++
|
||||||
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
keeper.handleValidatorSignature(ctx, val, false)
|
||||||
|
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||||
|
require.Equal(t, sdk.Bonded, validator.GetStatus())
|
||||||
|
|
||||||
|
// validator should be revoked again after 100 unsigned blocks
|
||||||
|
nextHeight := height + 100
|
||||||
|
for ; height <= nextHeight; height++ {
|
||||||
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
keeper.handleValidatorSignature(ctx, val, false)
|
||||||
|
}
|
||||||
|
validator, _ = sk.GetValidatorByPubKey(ctx, val)
|
||||||
|
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cdc = wire.NewCodec()
|
||||||
|
|
||||||
|
// name to identify transaction types
|
||||||
|
const MsgType = "slashing"
|
||||||
|
|
||||||
|
// verify interface at compile time
|
||||||
|
var _ sdk.Msg = &MsgUnrevoke{}
|
||||||
|
|
||||||
|
// MsgUnrevoke - struct for unrevoking revoked validator
|
||||||
|
type MsgUnrevoke struct {
|
||||||
|
ValidatorAddr sdk.Address `json:"address"` // address of the validator owner
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMsgUnrevoke(validatorAddr sdk.Address) MsgUnrevoke {
|
||||||
|
return MsgUnrevoke{
|
||||||
|
ValidatorAddr: validatorAddr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint
|
||||||
|
func (msg MsgUnrevoke) Type() string { return MsgType }
|
||||||
|
func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} }
|
||||||
|
|
||||||
|
// get the bytes for the message signer to sign on
|
||||||
|
func (msg MsgUnrevoke) GetSignBytes() []byte {
|
||||||
|
b, err := cdc.MarshalJSON(msg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// quick validity check
|
||||||
|
func (msg MsgUnrevoke) ValidateBasic() sdk.Error {
|
||||||
|
if msg.ValidatorAddr == nil {
|
||||||
|
return ErrBadValidatorAddr(DefaultCodespace)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MaxEvidenceAge - Max age for evidence - 21 days (3 weeks)
|
||||||
|
// TODO Should this be a governance parameter or just modifiable with SoftwareUpgradeProposals?
|
||||||
|
// MaxEvidenceAge = 60 * 60 * 24 * 7 * 3
|
||||||
|
// TODO Temporarily set to 2 minutes for testnets.
|
||||||
|
MaxEvidenceAge int64 = 60 * 2
|
||||||
|
|
||||||
|
// SignedBlocksWindow - sliding window for downtime slashing
|
||||||
|
// TODO Governance parameter?
|
||||||
|
// TODO Temporarily set to 100 blocks for testnets
|
||||||
|
SignedBlocksWindow int64 = 100
|
||||||
|
|
||||||
|
// Downtime slashing threshold - 50%
|
||||||
|
// TODO Governance parameter?
|
||||||
|
MinSignedPerWindow int64 = SignedBlocksWindow / 2
|
||||||
|
|
||||||
|
// Downtime unbond duration
|
||||||
|
// TODO Governance parameter?
|
||||||
|
// TODO Temporarily set to 10 minutes for testnets
|
||||||
|
DowntimeUnbondDuration int64 = 60 * 10
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// SlashFractionDoubleSign - currently 5%
|
||||||
|
// TODO Governance parameter?
|
||||||
|
SlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20))
|
||||||
|
|
||||||
|
// SlashFractionDowntime - currently 1%
|
||||||
|
// TODO Governance parameter?
|
||||||
|
SlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100))
|
||||||
|
)
|
|
@ -0,0 +1,74 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Stored by *validator* address (not owner address)
|
||||||
|
func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.Address) (info ValidatorSigningInfo, found bool) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
bz := store.Get(GetValidatorSigningInfoKey(address))
|
||||||
|
if bz == nil {
|
||||||
|
found = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
k.cdc.MustUnmarshalBinary(bz, &info)
|
||||||
|
found = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stored by *validator* address (not owner address)
|
||||||
|
func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.Address, info ValidatorSigningInfo) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
bz := k.cdc.MustMarshalBinary(info)
|
||||||
|
store.Set(GetValidatorSigningInfoKey(address), bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stored by *validator* address (not owner address)
|
||||||
|
func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64) (signed bool) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
bz := store.Get(GetValidatorSigningBitArrayKey(address, index))
|
||||||
|
if bz == nil {
|
||||||
|
// lazy: treat empty key as unsigned
|
||||||
|
signed = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
k.cdc.MustUnmarshalBinary(bz, &signed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stored by *validator* address (not owner address)
|
||||||
|
func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.Address, index int64, signed bool) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
bz := k.cdc.MustMarshalBinary(signed)
|
||||||
|
store.Set(GetValidatorSigningBitArrayKey(address, index), bz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signing info for a validator
|
||||||
|
type ValidatorSigningInfo struct {
|
||||||
|
StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unrevoked
|
||||||
|
IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array
|
||||||
|
JailedUntil int64 `json:"jailed_until"` // timestamp validator cannot be unrevoked until
|
||||||
|
SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return human readable signing info
|
||||||
|
func (i ValidatorSigningInfo) HumanReadableString() string {
|
||||||
|
return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %d, signed blocks counter: %d",
|
||||||
|
i.StartHeight, i.IndexOffset, i.JailedUntil, i.SignedBlocksCounter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stored by *validator* address (not owner address)
|
||||||
|
func GetValidatorSigningInfoKey(v sdk.Address) []byte {
|
||||||
|
return append([]byte{0x01}, v.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stored by *validator* address (not owner address)
|
||||||
|
func GetValidatorSigningBitArrayKey(v sdk.Address, i int64) []byte {
|
||||||
|
b := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(b, uint64(i))
|
||||||
|
return append([]byte{0x02}, append(v.Bytes(), b...)...)
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetSetValidatorSigningInfo(t *testing.T) {
|
||||||
|
ctx, _, _, keeper := createTestInput(t)
|
||||||
|
info, found := keeper.getValidatorSigningInfo(ctx, addrs[0])
|
||||||
|
require.False(t, found)
|
||||||
|
newInfo := ValidatorSigningInfo{
|
||||||
|
StartHeight: int64(4),
|
||||||
|
IndexOffset: int64(3),
|
||||||
|
JailedUntil: int64(2),
|
||||||
|
SignedBlocksCounter: int64(10),
|
||||||
|
}
|
||||||
|
keeper.setValidatorSigningInfo(ctx, addrs[0], newInfo)
|
||||||
|
info, found = keeper.getValidatorSigningInfo(ctx, addrs[0])
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, info.StartHeight, int64(4))
|
||||||
|
require.Equal(t, info.IndexOffset, int64(3))
|
||||||
|
require.Equal(t, info.JailedUntil, int64(2))
|
||||||
|
require.Equal(t, info.SignedBlocksCounter, int64(10))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSetValidatorSigningBitArray(t *testing.T) {
|
||||||
|
ctx, _, _, keeper := createTestInput(t)
|
||||||
|
signed := keeper.getValidatorSigningBitArray(ctx, addrs[0], 0)
|
||||||
|
require.False(t, signed) // treat empty key as unsigned
|
||||||
|
keeper.setValidatorSigningBitArray(ctx, addrs[0], 0, true)
|
||||||
|
signed = keeper.getValidatorSigningBitArray(ctx, addrs[0], 0)
|
||||||
|
require.True(t, signed) // now should be signed
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
|
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/stake"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
addrs = []sdk.Address{
|
||||||
|
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"),
|
||||||
|
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"),
|
||||||
|
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162"),
|
||||||
|
}
|
||||||
|
pks = []crypto.PubKey{
|
||||||
|
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"),
|
||||||
|
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"),
|
||||||
|
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"),
|
||||||
|
}
|
||||||
|
initCoins int64 = 200
|
||||||
|
)
|
||||||
|
|
||||||
|
func createTestCodec() *wire.Codec {
|
||||||
|
cdc := wire.NewCodec()
|
||||||
|
sdk.RegisterWire(cdc)
|
||||||
|
auth.RegisterWire(cdc)
|
||||||
|
bank.RegisterWire(cdc)
|
||||||
|
stake.RegisterWire(cdc)
|
||||||
|
wire.RegisterCrypto(cdc)
|
||||||
|
return cdc
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keeper) {
|
||||||
|
keyAcc := sdk.NewKVStoreKey("acc")
|
||||||
|
keyStake := sdk.NewKVStoreKey("stake")
|
||||||
|
keySlashing := sdk.NewKVStoreKey("slashing")
|
||||||
|
db := dbm.NewMemDB()
|
||||||
|
ms := store.NewCommitMultiStore(db)
|
||||||
|
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
|
||||||
|
ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db)
|
||||||
|
ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db)
|
||||||
|
err := ms.LoadLatestVersion()
|
||||||
|
require.Nil(t, err)
|
||||||
|
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewTMLogger(os.Stdout))
|
||||||
|
cdc := createTestCodec()
|
||||||
|
accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{})
|
||||||
|
ck := bank.NewKeeper(accountMapper)
|
||||||
|
sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace)
|
||||||
|
genesis := stake.DefaultGenesisState()
|
||||||
|
genesis.Pool.LooseUnbondedTokens = initCoins * int64(len(addrs))
|
||||||
|
stake.InitGenesis(ctx, sk, genesis)
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ck.AddCoins(ctx, addr, sdk.Coins{
|
||||||
|
{sk.GetParams(ctx).BondDenom, initCoins},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
keeper := NewKeeper(cdc, keySlashing, sk, DefaultCodespace)
|
||||||
|
return ctx, ck, sk, keeper
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPubKey(pk string) (res crypto.PubKey) {
|
||||||
|
pkBytes, err := hex.DecodeString(pk)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
var pkEd crypto.PubKeyEd25519
|
||||||
|
copy(pkEd[:], pkBytes[:])
|
||||||
|
return pkEd
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAddr(addr string) sdk.Address {
|
||||||
|
res := []byte(addr)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestMsgCreateValidator(address sdk.Address, pubKey crypto.PubKey, amt int64) stake.MsgCreateValidator {
|
||||||
|
return stake.MsgCreateValidator{
|
||||||
|
Description: stake.Description{},
|
||||||
|
ValidatorAddr: address,
|
||||||
|
PubKey: pubKey,
|
||||||
|
Bond: sdk.Coin{"steak", amt},
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// slashing begin block functionality
|
||||||
|
func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags sdk.Tags) {
|
||||||
|
// Tag the height
|
||||||
|
heightBytes := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(heightBytes, uint64(req.Header.Height))
|
||||||
|
tags = sdk.NewTags("height", heightBytes)
|
||||||
|
|
||||||
|
// Deal with any equivocation evidence
|
||||||
|
for _, evidence := range req.ByzantineValidators {
|
||||||
|
pk, err := tmtypes.PB2TM.PubKey(evidence.Validator.PubKey)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
switch string(evidence.Type) {
|
||||||
|
case tmtypes.ABCIEvidenceTypeDuplicateVote:
|
||||||
|
sk.handleDoubleSign(ctx, evidence.Height, evidence.Time, pk)
|
||||||
|
default:
|
||||||
|
ctx.Logger().With("module", "x/slashing").Error(fmt.Sprintf("Ignored unknown evidence type: %s", string(evidence.Type)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over all the validators which *should* have signed this block
|
||||||
|
for _, validator := range req.Validators {
|
||||||
|
present := validator.SignedLastBlock
|
||||||
|
pubkey, err := tmtypes.PB2TM.PubKey(validator.Validator.PubKey)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
sk.handleValidatorSignature(ctx, pubkey, present)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBeginBlocker(t *testing.T) {
|
||||||
|
ctx, ck, sk, keeper := createTestInput(t)
|
||||||
|
addr, pk, amt := addrs[2], pks[2], int64(100)
|
||||||
|
|
||||||
|
// bond the validator
|
||||||
|
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, pk, amt))
|
||||||
|
require.True(t, got.IsOK())
|
||||||
|
stake.EndBlocker(ctx, sk)
|
||||||
|
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}})
|
||||||
|
require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower())
|
||||||
|
|
||||||
|
val := abci.Validator{
|
||||||
|
PubKey: tmtypes.TM2PB.PubKey(pk),
|
||||||
|
Power: amt,
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark the validator as having signed
|
||||||
|
req := abci.RequestBeginBlock{
|
||||||
|
Validators: []abci.SigningValidator{{
|
||||||
|
Validator: val,
|
||||||
|
SignedLastBlock: true,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
BeginBlocker(ctx, req, keeper)
|
||||||
|
|
||||||
|
info, found := keeper.getValidatorSigningInfo(ctx, pk.Address())
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, ctx.BlockHeight(), info.StartHeight)
|
||||||
|
require.Equal(t, int64(1), info.IndexOffset)
|
||||||
|
require.Equal(t, int64(0), info.JailedUntil)
|
||||||
|
require.Equal(t, int64(1), info.SignedBlocksCounter)
|
||||||
|
|
||||||
|
height := int64(0)
|
||||||
|
|
||||||
|
// for 50 blocks, mark the validator as having signed
|
||||||
|
for ; height < 50; height++ {
|
||||||
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
req = abci.RequestBeginBlock{
|
||||||
|
Validators: []abci.SigningValidator{{
|
||||||
|
Validator: val,
|
||||||
|
SignedLastBlock: true,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
BeginBlocker(ctx, req, keeper)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for 51 blocks, mark the validator as having not signed
|
||||||
|
for ; height < 102; height++ {
|
||||||
|
ctx = ctx.WithBlockHeight(height)
|
||||||
|
req = abci.RequestBeginBlock{
|
||||||
|
Validators: []abci.SigningValidator{{
|
||||||
|
Validator: val,
|
||||||
|
SignedLastBlock: false,
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
BeginBlocker(ctx, req, keeper)
|
||||||
|
}
|
||||||
|
|
||||||
|
// validator should be revoked
|
||||||
|
validator, found := sk.GetValidatorByPubKey(ctx, pk)
|
||||||
|
require.True(t, found)
|
||||||
|
require.Equal(t, sdk.Unbonded, validator.GetStatus())
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package slashing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register concrete types on wire codec
|
||||||
|
func RegisterWire(cdc *wire.Codec) {
|
||||||
|
cdc.RegisterConcrete(MsgUnrevoke{}, "cosmos-sdk/MsgUnrevoke", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var cdcEmpty = wire.NewCodec()
|
|
@ -21,7 +21,7 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
addr, err := sdk.GetAccAddressBech32Cosmos(args[0])
|
addr, err := sdk.GetAccAddressBech32(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -72,25 +72,25 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse out the candidates
|
// parse out the validators
|
||||||
var candidates []stake.Validator
|
var validators []stake.Validator
|
||||||
for _, KV := range resKVs {
|
for _, KV := range resKVs {
|
||||||
var validator stake.Validator
|
var validator stake.Validator
|
||||||
cdc.MustUnmarshalBinary(KV.Value, &validator)
|
cdc.MustUnmarshalBinary(KV.Value, &validator)
|
||||||
candidates = append(candidates, validator)
|
validators = append(validators, validator)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch viper.Get(cli.OutputFlag) {
|
switch viper.Get(cli.OutputFlag) {
|
||||||
case "text":
|
case "text":
|
||||||
for _, candidate := range candidates {
|
for _, validator := range validators {
|
||||||
resp, err := candidate.HumanReadableString()
|
resp, err := validator.HumanReadableString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(resp)
|
fmt.Println(resp)
|
||||||
}
|
}
|
||||||
case "json":
|
case "json":
|
||||||
output, err := wire.MarshalJSONIndent(cdc, candidates)
|
output, err := wire.MarshalJSONIndent(cdc, validators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
Short: "Query a delegations bond based on address and validator address",
|
Short: "Query a delegations bond based on address and validator address",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
addr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator))
|
addr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the command to query all the candidates bonded to a delegation
|
// get the command to query all the validators bonded to a delegation
|
||||||
func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
|
func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "delegations [delegator-addr]",
|
Use: "delegations [delegator-addr]",
|
||||||
|
@ -165,7 +165,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(args[0])
|
delegatorAddr, err := sdk.GetAccAddressBech32(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse out the candidates
|
// parse out the validators
|
||||||
var delegations []stake.Delegation
|
var delegations []stake.Delegation
|
||||||
for _, KV := range resKVs {
|
for _, KV := range resKVs {
|
||||||
var delegation stake.Delegation
|
var delegation stake.Delegation
|
||||||
|
|
|
@ -13,8 +13,8 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
)
|
)
|
||||||
|
|
||||||
// create declare candidacy command
|
// create create validator command
|
||||||
func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "create-validator",
|
Use: "create-validator",
|
||||||
Short: "create new validator initialized with a self-delegation to it",
|
Short: "create new validator initialized with a self-delegation to it",
|
||||||
|
@ -25,7 +25,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator))
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
||||||
if len(pkStr) == 0 {
|
if len(pkStr) == 0 {
|
||||||
return fmt.Errorf("must use --pubkey flag")
|
return fmt.Errorf("must use --pubkey flag")
|
||||||
}
|
}
|
||||||
pk, err := sdk.GetValPubKeyBech32Cosmos(pkStr)
|
pk, err := sdk.GetValPubKeyBech32(pkStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
||||||
Website: viper.GetString(FlagWebsite),
|
Website: viper.GetString(FlagWebsite),
|
||||||
Details: viper.GetString(FlagDetails),
|
Details: viper.GetString(FlagDetails),
|
||||||
}
|
}
|
||||||
msg := stake.NewMsgDeclareCandidacy(validatorAddr, pk, amount, description)
|
msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)
|
||||||
|
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, msg, cdc)
|
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, msg, cdc)
|
||||||
|
@ -67,14 +67,14 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// create edit candidacy command
|
// create edit validator command
|
||||||
func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command {
|
func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "edit-validator",
|
Use: "edit-validator",
|
||||||
Short: "edit and existing validator account",
|
Short: "edit and existing validator account",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator))
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command {
|
||||||
Website: viper.GetString(FlagWebsite),
|
Website: viper.GetString(FlagWebsite),
|
||||||
Details: viper.GetString(FlagDetails),
|
Details: viper.GetString(FlagDetails),
|
||||||
}
|
}
|
||||||
msg := stake.NewMsgEditCandidacy(validatorAddr, description)
|
msg := stake.NewMsgEditValidator(validatorAddr, description)
|
||||||
|
|
||||||
// build and sign the transaction, then broadcast to Tendermint
|
// build and sign the transaction, then broadcast to Tendermint
|
||||||
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
||||||
|
@ -104,7 +104,7 @@ func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// create edit candidacy command
|
// create edit validator command
|
||||||
func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "delegate",
|
Use: "delegate",
|
||||||
|
@ -115,8 +115,8 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressDelegator))
|
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
||||||
validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator))
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// create edit candidacy command
|
// create edit validator command
|
||||||
func GetCmdUnbond(cdc *wire.Codec) *cobra.Command {
|
func GetCmdUnbond(cdc *wire.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "unbond",
|
Use: "unbond",
|
||||||
|
@ -163,8 +163,8 @@ func GetCmdUnbond(cdc *wire.Codec) *cobra.Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressDelegator))
|
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
||||||
validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator))
|
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package rest
|
package rest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/tendermint/go-crypto/keys"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -14,34 +12,39 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegisterRoutes - Central function to define routes that get registered by the main application
|
func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
|
||||||
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
|
r.HandleFunc(
|
||||||
r.HandleFunc("/stake/{delegator}/bonding_status/{validator}", BondingStatusHandlerFn("stake", cdc, kb, ctx)).Methods("GET")
|
"/stake/{delegator}/bonding_status/{validator}",
|
||||||
|
bondingStatusHandlerFn(ctx, "stake", cdc),
|
||||||
|
).Methods("GET")
|
||||||
|
r.HandleFunc(
|
||||||
|
"/stake/validators",
|
||||||
|
validatorsHandlerFn(ctx, "stake", cdc),
|
||||||
|
).Methods("GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
// BondingStatusHandlerFn - http request handler to query delegator bonding status
|
// http request handler to query delegator bonding status
|
||||||
func BondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
|
func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// read parameters
|
// read parameters
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
delegator := vars["delegator"]
|
bech32delegator := vars["delegator"]
|
||||||
validator := vars["validator"]
|
bech32validator := vars["validator"]
|
||||||
|
|
||||||
bz, err := hex.DecodeString(delegator)
|
delegatorAddr, err := sdk.GetAccAddressBech32(bech32delegator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delegatorAddr := sdk.Address(bz)
|
|
||||||
|
|
||||||
bz, err = hex.DecodeString(validator)
|
validatorAddr, err := sdk.GetValAddressBech32(bech32validator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
validatorAddr := sdk.Address(bz)
|
|
||||||
|
|
||||||
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
|
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
|
||||||
|
|
||||||
|
@ -76,3 +79,103 @@ func BondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase,
|
||||||
w.Write(output)
|
w.Write(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO inherit from Validator
|
||||||
|
type StakeValidatorOutput struct {
|
||||||
|
Owner string `json:"owner"` // in bech32
|
||||||
|
PubKey string `json:"pub_key"` // in bech32
|
||||||
|
Revoked bool `json:"revoked"` // has the validator been revoked from bonded status?
|
||||||
|
|
||||||
|
PoolShares stake.PoolShares `json:"pool_shares"` // total shares for tokens held in the pool
|
||||||
|
DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators
|
||||||
|
|
||||||
|
Description stake.Description `json:"description"` // description terms for the validator
|
||||||
|
BondHeight int64 `json:"bond_height"` // earliest height as a bonded validator
|
||||||
|
BondIntraTxCounter int16 `json:"bond_intra_tx_counter"` // block-local tx index of validator change
|
||||||
|
ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer
|
||||||
|
|
||||||
|
Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators
|
||||||
|
CommissionMax sdk.Rat `json:"commission_max"` // XXX maximum commission rate which this validator can ever charge
|
||||||
|
CommissionChangeRate sdk.Rat `json:"commission_change_rate"` // XXX maximum daily increase of the validator commission
|
||||||
|
CommissionChangeToday sdk.Rat `json:"commission_change_today"` // XXX commission rate change today, reset each day (UTC time)
|
||||||
|
|
||||||
|
// fee related
|
||||||
|
PrevBondedShares sdk.Rat `json:"prev_bonded_shares"` // total shares of a global hold pools
|
||||||
|
}
|
||||||
|
|
||||||
|
func bech32StakeValidatorOutput(validator stake.Validator) (StakeValidatorOutput, error) {
|
||||||
|
bechOwner, err := sdk.Bech32ifyVal(validator.Owner)
|
||||||
|
if err != nil {
|
||||||
|
return StakeValidatorOutput{}, err
|
||||||
|
}
|
||||||
|
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
|
||||||
|
if err != nil {
|
||||||
|
return StakeValidatorOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return StakeValidatorOutput{
|
||||||
|
Owner: bechOwner,
|
||||||
|
PubKey: bechValPubkey,
|
||||||
|
Revoked: validator.Revoked,
|
||||||
|
|
||||||
|
PoolShares: validator.PoolShares,
|
||||||
|
DelegatorShares: validator.DelegatorShares,
|
||||||
|
|
||||||
|
Description: validator.Description,
|
||||||
|
BondHeight: validator.BondHeight,
|
||||||
|
BondIntraTxCounter: validator.BondIntraTxCounter,
|
||||||
|
ProposerRewardPool: validator.ProposerRewardPool,
|
||||||
|
|
||||||
|
Commission: validator.Commission,
|
||||||
|
CommissionMax: validator.CommissionMax,
|
||||||
|
CommissionChangeRate: validator.CommissionChangeRate,
|
||||||
|
CommissionChangeToday: validator.CommissionChangeToday,
|
||||||
|
|
||||||
|
PrevBondedShares: validator.PrevBondedShares,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO bech32
|
||||||
|
// http request handler to query list of validators
|
||||||
|
func validatorsHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
kvs, err := ctx.QuerySubspace(cdc, stake.ValidatorsKey, storeName)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Couldn't query validators. Error: %s", err.Error())))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// the query will return empty if there are no validators
|
||||||
|
if len(kvs) == 0 {
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse out the validators
|
||||||
|
validators := make([]StakeValidatorOutput, len(kvs))
|
||||||
|
for i, kv := range kvs {
|
||||||
|
var validator stake.Validator
|
||||||
|
var bech32Validator StakeValidatorOutput
|
||||||
|
err = cdc.UnmarshalBinary(kv.Value, &validator)
|
||||||
|
if err == nil {
|
||||||
|
bech32Validator, err = bech32StakeValidatorOutput(validator)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
validators[i] = bech32Validator
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := cdc.MarshalJSON(validators)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/tendermint/go-crypto/keys"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterRoutes registers staking-related REST handlers to a router
|
||||||
|
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
|
||||||
|
registerQueryRoutes(ctx, r, cdc)
|
||||||
|
registerTxRoutes(ctx, r, cdc, kb)
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/tendermint/go-crypto/keys"
|
||||||
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
|
||||||
|
r.HandleFunc(
|
||||||
|
"/stake/delegations",
|
||||||
|
editDelegationsRequestHandlerFn(cdc, kb, ctx),
|
||||||
|
).Methods("POST")
|
||||||
|
}
|
||||||
|
|
||||||
|
type msgDelegateInput struct {
|
||||||
|
DelegatorAddr string `json:"delegator_addr"` // in bech32
|
||||||
|
ValidatorAddr string `json:"validator_addr"` // in bech32
|
||||||
|
Bond sdk.Coin `json:"bond"`
|
||||||
|
}
|
||||||
|
type msgUnbondInput struct {
|
||||||
|
DelegatorAddr string `json:"delegator_addr"` // in bech32
|
||||||
|
ValidatorAddr string `json:"validator_addr"` // in bech32
|
||||||
|
Shares string `json:"shares"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type editDelegationsBody struct {
|
||||||
|
LocalAccountName string `json:"name"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ChainID string `json:"chain_id"`
|
||||||
|
Sequence int64 `json:"sequence"`
|
||||||
|
Delegate []msgDelegateInput `json:"delegate"`
|
||||||
|
Unbond []msgUnbondInput `json:"unbond"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var m editDelegationsBody
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &m)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := kb.Get(m.LocalAccountName)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// build messages
|
||||||
|
messages := make([]sdk.Msg, len(m.Delegate)+len(m.Unbond))
|
||||||
|
i := 0
|
||||||
|
for _, msg := range m.Delegate {
|
||||||
|
delegatorAddr, err := sdk.GetAccAddressBech32(msg.DelegatorAddr)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
validatorAddr, err := sdk.GetValAddressBech32(msg.ValidatorAddr)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !bytes.Equal(info.Address(), delegatorAddr) {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
w.Write([]byte("Must use own delegator address"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
messages[i] = stake.MsgDelegate{
|
||||||
|
DelegatorAddr: delegatorAddr,
|
||||||
|
ValidatorAddr: validatorAddr,
|
||||||
|
Bond: msg.Bond,
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for _, msg := range m.Unbond {
|
||||||
|
delegatorAddr, err := sdk.GetAccAddressBech32(msg.DelegatorAddr)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
validatorAddr, err := sdk.GetValAddressBech32(msg.ValidatorAddr)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !bytes.Equal(info.Address(), delegatorAddr) {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
w.Write([]byte("Must use own delegator address"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
messages[i] = stake.MsgUnbond{
|
||||||
|
DelegatorAddr: delegatorAddr,
|
||||||
|
ValidatorAddr: validatorAddr,
|
||||||
|
Shares: msg.Shares,
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign messages
|
||||||
|
signedTxs := make([][]byte, len(messages[:]))
|
||||||
|
for i, msg := range messages {
|
||||||
|
// increment sequence for each message
|
||||||
|
ctx = ctx.WithSequence(m.Sequence)
|
||||||
|
m.Sequence++
|
||||||
|
|
||||||
|
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, msg, cdc)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
signedTxs[i] = txBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// send
|
||||||
|
// XXX the operation might not be atomic if a tx fails
|
||||||
|
// should we have a sdk.MultiMsg type to make sending atomic?
|
||||||
|
results := make([]*ctypes.ResultBroadcastTxCommit, len(signedTxs[:]))
|
||||||
|
for i, txBytes := range signedTxs {
|
||||||
|
res, err := ctx.BroadcastTx(txBytes)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
results[i] = res
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := json.MarshalIndent(results[:], "", " ")
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(output)
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,11 +35,11 @@ func (b Delegation) GetBondShares() sdk.Rat { return b.Shares }
|
||||||
|
|
||||||
//Human Friendly pretty printer
|
//Human Friendly pretty printer
|
||||||
func (b Delegation) HumanReadableString() (string, error) {
|
func (b Delegation) HumanReadableString() (string, error) {
|
||||||
bechAcc, err := sdk.Bech32CosmosifyAcc(b.DelegatorAddr)
|
bechAcc, err := sdk.Bech32ifyAcc(b.DelegatorAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
bechVal, err := sdk.Bech32CosmosifyAcc(b.ValidatorAddr)
|
bechVal, err := sdk.Bech32ifyAcc(b.ValidatorAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ const (
|
||||||
CodeInvalidValidator CodeType = 201
|
CodeInvalidValidator CodeType = 201
|
||||||
CodeInvalidBond CodeType = 202
|
CodeInvalidBond CodeType = 202
|
||||||
CodeInvalidInput CodeType = 203
|
CodeInvalidInput CodeType = 203
|
||||||
|
CodeValidatorJailed CodeType = 204
|
||||||
CodeUnauthorized CodeType = sdk.CodeUnauthorized
|
CodeUnauthorized CodeType = sdk.CodeUnauthorized
|
||||||
CodeInternal CodeType = sdk.CodeInternal
|
CodeInternal CodeType = sdk.CodeInternal
|
||||||
CodeUnknownRequest CodeType = sdk.CodeUnknownRequest
|
CodeUnknownRequest CodeType = sdk.CodeUnknownRequest
|
||||||
|
@ -72,10 +73,10 @@ func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||||
return newError(codespace, CodeInvalidValidator, "Delegator does not exist for that address")
|
return newError(codespace, CodeInvalidValidator, "Delegator does not exist for that address")
|
||||||
}
|
}
|
||||||
func ErrValidatorExistsAddr(codespace sdk.CodespaceType) sdk.Error {
|
func ErrValidatorExistsAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||||
return newError(codespace, CodeInvalidValidator, "Validator already exist, cannot re-declare candidacy")
|
return newError(codespace, CodeInvalidValidator, "Validator already exist, cannot re-create validator")
|
||||||
}
|
}
|
||||||
func ErrValidatorRevoked(codespace sdk.CodespaceType) sdk.Error {
|
func ErrValidatorRevoked(codespace sdk.CodespaceType) sdk.Error {
|
||||||
return newError(codespace, CodeInvalidValidator, "Candidacy for this address is currently revoked")
|
return newError(codespace, CodeInvalidValidator, "Validator for this address is currently revoked")
|
||||||
}
|
}
|
||||||
func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error {
|
func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error {
|
||||||
return newError(codespace, CodeInvalidValidator, "Missing signature")
|
return newError(codespace, CodeInvalidValidator, "Missing signature")
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package stake
|
package stake
|
||||||
|
|
||||||
import sdk "github.com/cosmos/cosmos-sdk/types"
|
import (
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
// GenesisState - all staking state that must be provided at genesis
|
// GenesisState - all staking state that must be provided at genesis
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
|
@ -22,21 +26,32 @@ func NewGenesisState(pool Pool, params Params, validators []Validator, bonds []D
|
||||||
// get raw genesis raw message for testing
|
// get raw genesis raw message for testing
|
||||||
func DefaultGenesisState() GenesisState {
|
func DefaultGenesisState() GenesisState {
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Pool: initialPool(),
|
Pool: InitialPool(),
|
||||||
Params: defaultParams(),
|
Params: DefaultParams(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitGenesis - store genesis parameters
|
// InitGenesis - store genesis parameters
|
||||||
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
k.setPool(ctx, data.Pool)
|
k.setPool(ctx, data.Pool)
|
||||||
k.setNewParams(ctx, data.Params)
|
k.setNewParams(ctx, data.Params)
|
||||||
for _, validator := range data.Validators {
|
for _, validator := range data.Validators {
|
||||||
k.updateValidator(ctx, validator)
|
|
||||||
|
// set validator
|
||||||
|
k.setValidator(ctx, validator)
|
||||||
|
|
||||||
|
// manually set indexes for the first time
|
||||||
|
k.setValidatorByPubKeyIndex(ctx, validator)
|
||||||
|
k.setValidatorByPowerIndex(ctx, validator, data.Pool)
|
||||||
|
if validator.Status() == sdk.Bonded {
|
||||||
|
store.Set(GetValidatorsBondedKey(validator.PubKey), validator.Owner)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for _, bond := range data.Bonds {
|
for _, bond := range data.Bonds {
|
||||||
k.setDelegation(ctx, bond)
|
k.setDelegation(ctx, bond)
|
||||||
}
|
}
|
||||||
|
k.updateBondedValidatorsFull(ctx, store)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteGenesis - output genesis parameters
|
// WriteGenesis - output genesis parameters
|
||||||
|
@ -52,3 +67,16 @@ func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
||||||
bonds,
|
bonds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteValidators - output current validator set
|
||||||
|
func WriteValidators(ctx sdk.Context, k Keeper) (vals []tmtypes.GenesisValidator) {
|
||||||
|
k.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) {
|
||||||
|
vals = append(vals, tmtypes.GenesisValidator{
|
||||||
|
PubKey: validator.GetPubKey(),
|
||||||
|
Power: validator.GetPower().Evaluate(),
|
||||||
|
Name: validator.GetMoniker(),
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -11,10 +11,10 @@ func NewHandler(k Keeper) sdk.Handler {
|
||||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
// NOTE msg already has validate basic run
|
// NOTE msg already has validate basic run
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case MsgDeclareCandidacy:
|
case MsgCreateValidator:
|
||||||
return handleMsgDeclareCandidacy(ctx, msg, k)
|
return handleMsgCreateValidator(ctx, msg, k)
|
||||||
case MsgEditCandidacy:
|
case MsgEditValidator:
|
||||||
return handleMsgEditCandidacy(ctx, msg, k)
|
return handleMsgEditValidator(ctx, msg, k)
|
||||||
case MsgDelegate:
|
case MsgDelegate:
|
||||||
return handleMsgDelegate(ctx, msg, k)
|
return handleMsgDelegate(ctx, msg, k)
|
||||||
case MsgUnbond:
|
case MsgUnbond:
|
||||||
|
@ -25,13 +25,27 @@ func NewHandler(k Keeper) sdk.Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEndBlocker generates sdk.EndBlocker
|
// Called every block, process inflation, update validator set
|
||||||
// Performs tick functionality
|
func EndBlocker(ctx sdk.Context, k Keeper) (ValidatorUpdates []abci.Validator) {
|
||||||
func NewEndBlocker(k Keeper) sdk.EndBlocker {
|
pool := k.GetPool(ctx)
|
||||||
return func(ctx sdk.Context, req abci.RequestEndBlock) (res abci.ResponseEndBlock) {
|
|
||||||
res.ValidatorUpdates = k.Tick(ctx)
|
// Process Validator Provisions
|
||||||
return
|
blockTime := ctx.BlockHeader().Time // XXX assuming in seconds, confirm
|
||||||
|
if pool.InflationLastTime+blockTime >= 3600 {
|
||||||
|
pool.InflationLastTime = blockTime
|
||||||
|
pool = k.processProvisions(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// save the params
|
||||||
|
k.setPool(ctx, pool)
|
||||||
|
|
||||||
|
// reset the intra-transaction counter
|
||||||
|
k.setIntraTxCounter(ctx, 0)
|
||||||
|
|
||||||
|
// calculate validator set changes
|
||||||
|
ValidatorUpdates = k.getTendermintUpdates(ctx)
|
||||||
|
k.clearTendermintUpdates(ctx)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//_____________________________________________________________________
|
//_____________________________________________________________________
|
||||||
|
@ -39,7 +53,7 @@ func NewEndBlocker(k Keeper) sdk.EndBlocker {
|
||||||
// These functions assume everything has been authenticated,
|
// These functions assume everything has been authenticated,
|
||||||
// now we just perform action and save
|
// now we just perform action and save
|
||||||
|
|
||||||
func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keeper) sdk.Result {
|
func handleMsgCreateValidator(ctx sdk.Context, msg MsgCreateValidator, k Keeper) sdk.Result {
|
||||||
|
|
||||||
// check to see if the pubkey or sender has been registered before
|
// check to see if the pubkey or sender has been registered before
|
||||||
_, found := k.GetValidator(ctx, msg.ValidatorAddr)
|
_, found := k.GetValidator(ctx, msg.ValidatorAddr)
|
||||||
|
@ -55,8 +69,9 @@ func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keepe
|
||||||
|
|
||||||
validator := NewValidator(msg.ValidatorAddr, msg.PubKey, msg.Description)
|
validator := NewValidator(msg.ValidatorAddr, msg.PubKey, msg.Description)
|
||||||
k.setValidator(ctx, validator)
|
k.setValidator(ctx, validator)
|
||||||
|
k.setValidatorByPubKeyIndex(ctx, validator)
|
||||||
tags := sdk.NewTags(
|
tags := sdk.NewTags(
|
||||||
"action", []byte("declareCandidacy"),
|
"action", []byte("createValidator"),
|
||||||
"validator", msg.ValidatorAddr.Bytes(),
|
"validator", msg.ValidatorAddr.Bytes(),
|
||||||
"moniker", []byte(msg.Description.Moniker),
|
"moniker", []byte(msg.Description.Moniker),
|
||||||
"identity", []byte(msg.Description.Identity),
|
"identity", []byte(msg.Description.Identity),
|
||||||
|
@ -74,7 +89,7 @@ func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keepe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk.Result {
|
func handleMsgEditValidator(ctx sdk.Context, msg MsgEditValidator, k Keeper) sdk.Result {
|
||||||
|
|
||||||
// validator must already be registered
|
// validator must already be registered
|
||||||
validator, found := k.GetValidator(ctx, msg.ValidatorAddr)
|
validator, found := k.GetValidator(ctx, msg.ValidatorAddr)
|
||||||
|
@ -94,7 +109,7 @@ func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk
|
||||||
|
|
||||||
k.updateValidator(ctx, validator)
|
k.updateValidator(ctx, validator)
|
||||||
tags := sdk.NewTags(
|
tags := sdk.NewTags(
|
||||||
"action", []byte("editCandidacy"),
|
"action", []byte("editValidator"),
|
||||||
"validator", msg.ValidatorAddr.Bytes(),
|
"validator", msg.ValidatorAddr.Bytes(),
|
||||||
"moniker", []byte(msg.Description.Moniker),
|
"moniker", []byte(msg.Description.Moniker),
|
||||||
"identity", []byte(msg.Description.Identity),
|
"identity", []byte(msg.Description.Identity),
|
||||||
|
@ -206,14 +221,14 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result {
|
||||||
bond.Shares = bond.Shares.Sub(delShares)
|
bond.Shares = bond.Shares.Sub(delShares)
|
||||||
|
|
||||||
// remove the bond
|
// remove the bond
|
||||||
revokeCandidacy := false
|
revokeValidator := false
|
||||||
if bond.Shares.IsZero() {
|
if bond.Shares.IsZero() {
|
||||||
|
|
||||||
// if the bond is the owner of the validator then
|
// if the bond is the owner of the validator then
|
||||||
// trigger a revoke candidacy
|
// trigger a revoke validator
|
||||||
if bytes.Equal(bond.DelegatorAddr, validator.Owner) &&
|
if bytes.Equal(bond.DelegatorAddr, validator.Owner) &&
|
||||||
validator.Revoked == false {
|
validator.Revoked == false {
|
||||||
revokeCandidacy = true
|
revokeValidator = true
|
||||||
}
|
}
|
||||||
|
|
||||||
k.removeDelegation(ctx, bond)
|
k.removeDelegation(ctx, bond)
|
||||||
|
@ -232,7 +247,7 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result {
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
// revoke validator if necessary
|
// revoke validator if necessary
|
||||||
if revokeCandidacy {
|
if revokeValidator {
|
||||||
validator.Revoked = true
|
validator.Revoked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
|
|
||||||
//______________________________________________________________________
|
//______________________________________________________________________
|
||||||
|
|
||||||
func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) MsgDeclareCandidacy {
|
func newTestMsgCreateValidator(address sdk.Address, pubKey crypto.PubKey, amt int64) MsgCreateValidator {
|
||||||
return MsgDeclareCandidacy{
|
return MsgCreateValidator{
|
||||||
Description: Description{},
|
Description: Description{},
|
||||||
ValidatorAddr: address,
|
ValidatorAddr: address,
|
||||||
PubKey: pubKey,
|
PubKey: pubKey,
|
||||||
|
@ -33,13 +33,13 @@ func newTestMsgDelegate(delegatorAddr, validatorAddr sdk.Address, amt int64) Msg
|
||||||
|
|
||||||
//______________________________________________________________________
|
//______________________________________________________________________
|
||||||
|
|
||||||
func TestDuplicatesMsgDeclareCandidacy(t *testing.T) {
|
func TestDuplicatesMsgCreateValidator(t *testing.T) {
|
||||||
ctx, _, keeper := createTestInput(t, false, 1000)
|
ctx, _, keeper := createTestInput(t, false, 1000)
|
||||||
|
|
||||||
validatorAddr := addrs[0]
|
validatorAddr := addrs[0]
|
||||||
pk := pks[0]
|
pk := pks[0]
|
||||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pk, 10)
|
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pk, 10)
|
||||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
assert.True(t, got.IsOK(), "%v", got)
|
assert.True(t, got.IsOK(), "%v", got)
|
||||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
|
@ -51,8 +51,8 @@ func TestDuplicatesMsgDeclareCandidacy(t *testing.T) {
|
||||||
assert.Equal(t, Description{}, validator.Description)
|
assert.Equal(t, Description{}, validator.Description)
|
||||||
|
|
||||||
// one validator cannot bond twice
|
// one validator cannot bond twice
|
||||||
msgDeclareCandidacy.PubKey = pks[1]
|
msgCreateValidator.PubKey = pks[1]
|
||||||
got = handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
assert.False(t, got.IsOK(), "%v", got)
|
assert.False(t, got.IsOK(), "%v", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,10 +64,10 @@ func TestIncrementsMsgDelegate(t *testing.T) {
|
||||||
bondAmount := int64(10)
|
bondAmount := int64(10)
|
||||||
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
||||||
|
|
||||||
// first declare candidacy
|
// first create validator
|
||||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], bondAmount)
|
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], bondAmount)
|
||||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
assert.True(t, got.IsOK(), "expected declare candidacy msg to be ok, got %v", got)
|
assert.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got)
|
||||||
|
|
||||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
|
@ -134,12 +134,12 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
||||||
ctx, accMapper, keeper := createTestInput(t, false, initBond)
|
ctx, accMapper, keeper := createTestInput(t, false, initBond)
|
||||||
params := keeper.GetParams(ctx)
|
params := keeper.GetParams(ctx)
|
||||||
|
|
||||||
// declare candidacy, delegate
|
// create validator, delegate
|
||||||
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
||||||
|
|
||||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], initBond)
|
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], initBond)
|
||||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
assert.True(t, got.IsOK(), "expected declare-candidacy to be ok, got %v", got)
|
assert.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
|
||||||
|
|
||||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, initBond)
|
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, initBond)
|
||||||
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
got = handleMsgDelegate(ctx, msgDelegate, keeper)
|
||||||
|
@ -216,7 +216,7 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
||||||
"got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgUnbond, unbondSharesStr, leftBonded)
|
"got: %v\nmsgUnbond: %v\nshares: %v\nleftBonded: %v\n", got, msgUnbond, unbondSharesStr, leftBonded)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultipleMsgDeclareCandidacy(t *testing.T) {
|
func TestMultipleMsgCreateValidator(t *testing.T) {
|
||||||
initBond := int64(1000)
|
initBond := int64(1000)
|
||||||
ctx, accMapper, keeper := createTestInput(t, false, initBond)
|
ctx, accMapper, keeper := createTestInput(t, false, initBond)
|
||||||
params := keeper.GetParams(ctx)
|
params := keeper.GetParams(ctx)
|
||||||
|
@ -224,8 +224,8 @@ func TestMultipleMsgDeclareCandidacy(t *testing.T) {
|
||||||
|
|
||||||
// bond them all
|
// bond them all
|
||||||
for i, validatorAddr := range validatorAddrs {
|
for i, validatorAddr := range validatorAddrs {
|
||||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[i], 10)
|
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[i], 10)
|
||||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||||
|
|
||||||
//Check that the account is bonded
|
//Check that the account is bonded
|
||||||
|
@ -266,8 +266,8 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
||||||
validatorAddr, delegatorAddrs := addrs[0], addrs[1:]
|
validatorAddr, delegatorAddrs := addrs[0], addrs[1:]
|
||||||
|
|
||||||
//first make a validator
|
//first make a validator
|
||||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], 10)
|
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], 10)
|
||||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||||
|
|
||||||
// delegate multiple parties
|
// delegate multiple parties
|
||||||
|
@ -294,14 +294,14 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVoidCandidacy(t *testing.T) {
|
func TestRevokeValidator(t *testing.T) {
|
||||||
ctx, _, keeper := createTestInput(t, false, 1000)
|
ctx, _, keeper := createTestInput(t, false, 1000)
|
||||||
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
||||||
|
|
||||||
// create the validator
|
// create the validator
|
||||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], 10)
|
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], 10)
|
||||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
require.True(t, got.IsOK(), "expected no error on runMsgDeclareCandidacy")
|
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||||
|
|
||||||
// bond a delegator
|
// bond a delegator
|
||||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||||
|
@ -311,7 +311,7 @@ func TestVoidCandidacy(t *testing.T) {
|
||||||
// unbond the validators bond portion
|
// unbond the validators bond portion
|
||||||
msgUnbondValidator := NewMsgUnbond(validatorAddr, validatorAddr, "10")
|
msgUnbondValidator := NewMsgUnbond(validatorAddr, validatorAddr, "10")
|
||||||
got = handleMsgUnbond(ctx, msgUnbondValidator, keeper)
|
got = handleMsgUnbond(ctx, msgUnbondValidator, keeper)
|
||||||
require.True(t, got.IsOK(), "expected no error on runMsgDeclareCandidacy")
|
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.True(t, validator.Revoked)
|
require.True(t, validator.Revoked)
|
||||||
|
@ -323,9 +323,9 @@ func TestVoidCandidacy(t *testing.T) {
|
||||||
// test that the delegator can still withdraw their bonds
|
// test that the delegator can still withdraw their bonds
|
||||||
msgUnbondDelegator := NewMsgUnbond(delegatorAddr, validatorAddr, "10")
|
msgUnbondDelegator := NewMsgUnbond(delegatorAddr, validatorAddr, "10")
|
||||||
got = handleMsgUnbond(ctx, msgUnbondDelegator, keeper)
|
got = handleMsgUnbond(ctx, msgUnbondDelegator, keeper)
|
||||||
require.True(t, got.IsOK(), "expected no error on runMsgDeclareCandidacy")
|
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||||
|
|
||||||
// verify that the pubkey can now be reused
|
// verify that the pubkey can now be reused
|
||||||
got = handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||||
assert.True(t, got.IsOK(), "expected ok, got %v", got)
|
assert.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package stake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
abci "github.com/tendermint/abci/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -12,30 +11,6 @@ const (
|
||||||
|
|
||||||
var hrsPerYrRat = sdk.NewRat(hrsPerYr) // as defined by a julian year of 365.25 days
|
var hrsPerYrRat = sdk.NewRat(hrsPerYr) // as defined by a julian year of 365.25 days
|
||||||
|
|
||||||
// Tick - called at the end of every block
|
|
||||||
func (k Keeper) Tick(ctx sdk.Context) (change []abci.Validator) {
|
|
||||||
p := k.GetPool(ctx)
|
|
||||||
|
|
||||||
// Process Validator Provisions
|
|
||||||
blockTime := ctx.BlockHeader().Time // XXX assuming in seconds, confirm
|
|
||||||
if p.InflationLastTime+blockTime >= 3600 {
|
|
||||||
p.InflationLastTime = blockTime
|
|
||||||
p = k.processProvisions(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the params
|
|
||||||
k.setPool(ctx, p)
|
|
||||||
|
|
||||||
// reset the intra-transaction counter
|
|
||||||
k.setIntraTxCounter(ctx, 0)
|
|
||||||
|
|
||||||
// calculate validator set changes
|
|
||||||
change = k.getTendermintUpdates(ctx)
|
|
||||||
k.clearTendermintUpdates(ctx)
|
|
||||||
|
|
||||||
return change
|
|
||||||
}
|
|
||||||
|
|
||||||
// process provisions for an hour period
|
// process provisions for an hour period
|
||||||
func (k Keeper) processProvisions(ctx sdk.Context) Pool {
|
func (k Keeper) processProvisions(ctx sdk.Context) Pool {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// keeper of the staking store
|
// keeper of the staking store
|
||||||
|
@ -38,6 +39,16 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator Valid
|
||||||
return k.getValidator(store, addr)
|
return k.getValidator(store, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get a single validator by pubkey
|
||||||
|
func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (validator Validator, found bool) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
addr := store.Get(GetValidatorByPubKeyIndexKey(pubkey))
|
||||||
|
if addr == nil {
|
||||||
|
return validator, false
|
||||||
|
}
|
||||||
|
return k.getValidator(store, addr)
|
||||||
|
}
|
||||||
|
|
||||||
// get a single validator (reuse store)
|
// get a single validator (reuse store)
|
||||||
func (k Keeper) getValidator(store sdk.KVStore, addr sdk.Address) (validator Validator, found bool) {
|
func (k Keeper) getValidator(store sdk.KVStore, addr sdk.Address) (validator Validator, found bool) {
|
||||||
b := store.Get(GetValidatorKey(addr))
|
b := store.Get(GetValidatorKey(addr))
|
||||||
|
@ -51,10 +62,22 @@ func (k Keeper) getValidator(store sdk.KVStore, addr sdk.Address) (validator Val
|
||||||
// set the main record holding validator details
|
// set the main record holding validator details
|
||||||
func (k Keeper) setValidator(ctx sdk.Context, validator Validator) {
|
func (k Keeper) setValidator(ctx sdk.Context, validator Validator) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
// set main store
|
||||||
bz := k.cdc.MustMarshalBinary(validator)
|
bz := k.cdc.MustMarshalBinary(validator)
|
||||||
store.Set(GetValidatorKey(validator.Owner), bz)
|
store.Set(GetValidatorKey(validator.Owner), bz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k Keeper) setValidatorByPubKeyIndex(ctx sdk.Context, validator Validator) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
// set pointer by pubkey
|
||||||
|
store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Keeper) setValidatorByPowerIndex(ctx sdk.Context, validator Validator, pool Pool) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
store.Set(GetValidatorsByPowerKey(validator, pool), validator.Owner)
|
||||||
|
}
|
||||||
|
|
||||||
// Get the set of all validators with no limits, used during genesis dump
|
// Get the set of all validators with no limits, used during genesis dump
|
||||||
func (k Keeper) getAllValidators(ctx sdk.Context) (validators Validators) {
|
func (k Keeper) getAllValidators(ctx sdk.Context) (validators Validators) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
@ -203,8 +226,12 @@ func (k Keeper) updateValidator(ctx sdk.Context, validator Validator) Validator
|
||||||
oldValidator, oldFound := k.GetValidator(ctx, ownerAddr)
|
oldValidator, oldFound := k.GetValidator(ctx, ownerAddr)
|
||||||
|
|
||||||
if validator.Revoked && oldValidator.Status() == sdk.Bonded {
|
if validator.Revoked && oldValidator.Status() == sdk.Bonded {
|
||||||
validator, pool = validator.UpdateStatus(pool, sdk.Unbonded)
|
validator = k.unbondValidator(ctx, store, validator)
|
||||||
k.setPool(ctx, pool)
|
|
||||||
|
// need to also clear the cliff validator spot because the revoke has
|
||||||
|
// opened up a new spot which will be filled when
|
||||||
|
// updateValidatorsBonded is called
|
||||||
|
k.clearCliffValidator(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
powerIncreasing := false
|
powerIncreasing := false
|
||||||
|
@ -409,7 +436,7 @@ func (k Keeper) updateBondedValidatorsFull(ctx sdk.Context, store sdk.KVStore) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform all the store operations for when a validator status becomes unbonded
|
// perform all the store operations for when a validator status becomes unbonded
|
||||||
func (k Keeper) unbondValidator(ctx sdk.Context, store sdk.KVStore, validator Validator) {
|
func (k Keeper) unbondValidator(ctx sdk.Context, store sdk.KVStore, validator Validator) Validator {
|
||||||
pool := k.GetPool(ctx)
|
pool := k.GetPool(ctx)
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
|
@ -431,6 +458,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, store sdk.KVStore, validator Va
|
||||||
|
|
||||||
// also remove from the Bonded Validators Store
|
// also remove from the Bonded Validators Store
|
||||||
store.Delete(GetValidatorsBondedKey(validator.PubKey))
|
store.Delete(GetValidatorsBondedKey(validator.PubKey))
|
||||||
|
return validator
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform all the store operations for when a validator status becomes bonded
|
// perform all the store operations for when a validator status becomes bonded
|
||||||
|
@ -470,6 +498,7 @@ func (k Keeper) removeValidator(ctx sdk.Context, address sdk.Address) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
pool := k.getPool(store)
|
pool := k.getPool(store)
|
||||||
store.Delete(GetValidatorKey(address))
|
store.Delete(GetValidatorKey(address))
|
||||||
|
store.Delete(GetValidatorByPubKeyIndexKey(validator.PubKey))
|
||||||
store.Delete(GetValidatorsByPowerKey(validator, pool))
|
store.Delete(GetValidatorsByPowerKey(validator, pool))
|
||||||
|
|
||||||
// delete from the current and power weighted validator groups if the validator
|
// delete from the current and power weighted validator groups if the validator
|
||||||
|
@ -607,9 +636,9 @@ func (k Keeper) getPool(store sdk.KVStore) (pool Pool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k Keeper) setPool(ctx sdk.Context, p Pool) {
|
func (k Keeper) setPool(ctx sdk.Context, pool Pool) {
|
||||||
store := ctx.KVStore(k.storeKey)
|
store := ctx.KVStore(k.storeKey)
|
||||||
b := k.cdc.MustMarshalBinary(p)
|
b := k.cdc.MustMarshalBinary(pool)
|
||||||
store.Set(PoolKey, b)
|
store.Set(PoolKey, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,6 +685,13 @@ func (k Keeper) setCliffValidator(ctx sdk.Context, validator Validator, pool Poo
|
||||||
store.Set(ValidatorCliffKey, validator.Owner)
|
store.Set(ValidatorCliffKey, validator.Owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear the current validator and power of the validator on the cliff
|
||||||
|
func (k Keeper) clearCliffValidator(ctx sdk.Context) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
store.Delete(ValidatorPowerCliffKey)
|
||||||
|
store.Delete(ValidatorCliffKey)
|
||||||
|
}
|
||||||
|
|
||||||
//__________________________________________________________________________
|
//__________________________________________________________________________
|
||||||
|
|
||||||
// Implements ValidatorSet
|
// Implements ValidatorSet
|
||||||
|
@ -749,3 +785,46 @@ func (k Keeper) IterateDelegators(ctx sdk.Context, delAddr sdk.Address, fn func(
|
||||||
}
|
}
|
||||||
iterator.Close()
|
iterator.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// slash a validator
|
||||||
|
func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fraction sdk.Rat) {
|
||||||
|
// TODO height ignored for now, see https://github.com/cosmos/cosmos-sdk/pull/1011#issuecomment-390253957
|
||||||
|
logger := ctx.Logger().With("module", "x/stake")
|
||||||
|
val, found := k.GetValidatorByPubKey(ctx, pubkey)
|
||||||
|
if !found {
|
||||||
|
panic(fmt.Errorf("Attempted to slash a nonexistent validator with address %s", pubkey.Address()))
|
||||||
|
}
|
||||||
|
sharesToRemove := val.PoolShares.Amount.Mul(fraction)
|
||||||
|
pool := k.GetPool(ctx)
|
||||||
|
val, pool, burned := val.removePoolShares(pool, sharesToRemove)
|
||||||
|
k.setPool(ctx, pool) // update the pool
|
||||||
|
k.updateValidator(ctx, val) // update the validator, possibly kicking it out
|
||||||
|
logger.Info(fmt.Sprintf("Validator %s slashed by fraction %v, removed %v shares and burned %d tokens", pubkey.Address(), fraction, sharesToRemove, burned))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// revoke a validator
|
||||||
|
func (k Keeper) Revoke(ctx sdk.Context, pubkey crypto.PubKey) {
|
||||||
|
logger := ctx.Logger().With("module", "x/stake")
|
||||||
|
val, found := k.GetValidatorByPubKey(ctx, pubkey)
|
||||||
|
if !found {
|
||||||
|
panic(fmt.Errorf("Validator with pubkey %s not found, cannot revoke", pubkey))
|
||||||
|
}
|
||||||
|
val.Revoked = true
|
||||||
|
k.updateValidator(ctx, val) // update the validator, now revoked
|
||||||
|
logger.Info(fmt.Sprintf("Validator %s revoked", pubkey.Address()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// unrevoke a validator
|
||||||
|
func (k Keeper) Unrevoke(ctx sdk.Context, pubkey crypto.PubKey) {
|
||||||
|
logger := ctx.Logger().With("module", "x/stake")
|
||||||
|
val, found := k.GetValidatorByPubKey(ctx, pubkey)
|
||||||
|
if !found {
|
||||||
|
panic(fmt.Errorf("Validator with pubkey %s not found, cannot unrevoke", pubkey))
|
||||||
|
}
|
||||||
|
val.Revoked = false
|
||||||
|
k.updateValidator(ctx, val) // update the validator, now unrevoked
|
||||||
|
logger.Info(fmt.Sprintf("Validator %s unrevoked", pubkey.Address()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -16,13 +16,14 @@ var (
|
||||||
ParamKey = []byte{0x00} // key for parameters relating to staking
|
ParamKey = []byte{0x00} // key for parameters relating to staking
|
||||||
PoolKey = []byte{0x01} // key for the staking pools
|
PoolKey = []byte{0x01} // key for the staking pools
|
||||||
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
|
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
|
||||||
ValidatorsBondedKey = []byte{0x03} // prefix for each key to bonded/actively validating validators
|
ValidatorsByPubKeyIndexKey = []byte{0x03} // prefix for each key to a validator by pubkey
|
||||||
ValidatorsByPowerKey = []byte{0x04} // prefix for each key to a validator sorted by power
|
ValidatorsBondedKey = []byte{0x04} // prefix for each key to bonded/actively validating validators
|
||||||
ValidatorCliffKey = []byte{0x05} // key for block-local tx index
|
ValidatorsByPowerKey = []byte{0x05} // prefix for each key to a validator sorted by power
|
||||||
ValidatorPowerCliffKey = []byte{0x06} // key for block-local tx index
|
ValidatorCliffKey = []byte{0x06} // key for block-local tx index
|
||||||
TendermintUpdatesKey = []byte{0x07} // prefix for each key to a validator which is being updated
|
ValidatorPowerCliffKey = []byte{0x07} // key for block-local tx index
|
||||||
DelegationKey = []byte{0x08} // prefix for each key to a delegator's bond
|
TendermintUpdatesKey = []byte{0x08} // prefix for each key to a validator which is being updated
|
||||||
IntraTxCounterKey = []byte{0x09} // key for block-local tx index
|
DelegationKey = []byte{0x09} // prefix for each key to a delegator's bond
|
||||||
|
IntraTxCounterKey = []byte{0x10} // key for block-local tx index
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
|
||||||
|
@ -32,6 +33,11 @@ func GetValidatorKey(ownerAddr sdk.Address) []byte {
|
||||||
return append(ValidatorsKey, ownerAddr.Bytes()...)
|
return append(ValidatorsKey, ownerAddr.Bytes()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the key for the validator with pubkey
|
||||||
|
func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte {
|
||||||
|
return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
// get the key for the current validator group, ordered like tendermint
|
// get the key for the current validator group, ordered like tendermint
|
||||||
func GetValidatorsBondedKey(pk crypto.PubKey) []byte {
|
func GetValidatorsBondedKey(pk crypto.PubKey) []byte {
|
||||||
addr := pk.Address()
|
addr := pk.Address()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -463,8 +464,8 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) {
|
||||||
|
|
||||||
updates = keeper.getTendermintUpdates(ctx)
|
updates = keeper.getTendermintUpdates(ctx)
|
||||||
require.Equal(t, 2, len(updates))
|
require.Equal(t, 2, len(updates))
|
||||||
assert.Equal(t, validators[0].PubKey.Bytes(), updates[0].PubKey)
|
assert.Equal(t, tmtypes.TM2PB.PubKey(validators[0].PubKey), updates[0].PubKey)
|
||||||
assert.Equal(t, validators[1].PubKey.Bytes(), updates[1].PubKey)
|
assert.Equal(t, tmtypes.TM2PB.PubKey(validators[1].PubKey), updates[1].PubKey)
|
||||||
assert.Equal(t, int64(0), updates[0].Power)
|
assert.Equal(t, int64(0), updates[0].Power)
|
||||||
assert.Equal(t, int64(0), updates[1].Power)
|
assert.Equal(t, int64(0), updates[1].Power)
|
||||||
}
|
}
|
||||||
|
@ -586,7 +587,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) {
|
||||||
|
|
||||||
func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) {
|
func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) {
|
||||||
ctx, _, keeper := createTestInput(t, false, 0)
|
ctx, _, keeper := createTestInput(t, false, 0)
|
||||||
params := defaultParams()
|
params := DefaultParams()
|
||||||
params.MaxValidators = 2
|
params.MaxValidators = 2
|
||||||
keeper.setParams(ctx, params)
|
keeper.setParams(ctx, params)
|
||||||
|
|
||||||
|
@ -721,7 +722,7 @@ func TestBond(t *testing.T) {
|
||||||
|
|
||||||
func TestParams(t *testing.T) {
|
func TestParams(t *testing.T) {
|
||||||
ctx, _, keeper := createTestInput(t, false, 0)
|
ctx, _, keeper := createTestInput(t, false, 0)
|
||||||
expParams := defaultParams()
|
expParams := DefaultParams()
|
||||||
|
|
||||||
//check that the empty keeper loads the default
|
//check that the empty keeper loads the default
|
||||||
resParams := keeper.GetParams(ctx)
|
resParams := keeper.GetParams(ctx)
|
||||||
|
@ -736,7 +737,7 @@ func TestParams(t *testing.T) {
|
||||||
|
|
||||||
func TestPool(t *testing.T) {
|
func TestPool(t *testing.T) {
|
||||||
ctx, _, keeper := createTestInput(t, false, 0)
|
ctx, _, keeper := createTestInput(t, false, 0)
|
||||||
expPool := initialPool()
|
expPool := InitialPool()
|
||||||
|
|
||||||
//check that the empty keeper loads the default
|
//check that the empty keeper loads the default
|
||||||
resPool := keeper.GetPool(ctx)
|
resPool := keeper.GetPool(ctx)
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package stake
|
package stake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
|
||||||
crypto "github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,27 +15,21 @@ const MsgType = "stake"
|
||||||
const StakingToken = "steak"
|
const StakingToken = "steak"
|
||||||
|
|
||||||
//Verify interface at compile time
|
//Verify interface at compile time
|
||||||
var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelegate{}, &MsgUnbond{}
|
var _, _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{}, &MsgUnbond{}
|
||||||
|
|
||||||
var msgCdc = wire.NewCodec()
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
wire.RegisterCrypto(msgCdc)
|
|
||||||
}
|
|
||||||
|
|
||||||
//______________________________________________________________________
|
//______________________________________________________________________
|
||||||
|
|
||||||
// MsgDeclareCandidacy - struct for unbonding transactions
|
// MsgCreateValidator - struct for unbonding transactions
|
||||||
type MsgDeclareCandidacy struct {
|
type MsgCreateValidator struct {
|
||||||
Description
|
Description
|
||||||
ValidatorAddr sdk.Address `json:"address"`
|
ValidatorAddr sdk.Address `json:"address"`
|
||||||
PubKey crypto.PubKey `json:"pubkey"`
|
PubKey crypto.PubKey `json:"pubkey"`
|
||||||
Bond sdk.Coin `json:"bond"`
|
Bond sdk.Coin `json:"bond"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMsgDeclareCandidacy(validatorAddr sdk.Address, pubkey crypto.PubKey,
|
func NewMsgCreateValidator(validatorAddr sdk.Address, pubkey crypto.PubKey,
|
||||||
bond sdk.Coin, description Description) MsgDeclareCandidacy {
|
bond sdk.Coin, description Description) MsgCreateValidator {
|
||||||
return MsgDeclareCandidacy{
|
return MsgCreateValidator{
|
||||||
Description: description,
|
Description: description,
|
||||||
ValidatorAddr: validatorAddr,
|
ValidatorAddr: validatorAddr,
|
||||||
PubKey: pubkey,
|
PubKey: pubkey,
|
||||||
|
@ -47,18 +38,18 @@ func NewMsgDeclareCandidacy(validatorAddr sdk.Address, pubkey crypto.PubKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint
|
//nolint
|
||||||
func (msg MsgDeclareCandidacy) Type() string { return MsgType } //TODO update "stake/declarecandidacy"
|
func (msg MsgCreateValidator) Type() string { return MsgType }
|
||||||
func (msg MsgDeclareCandidacy) GetSigners() []sdk.Address {
|
func (msg MsgCreateValidator) GetSigners() []sdk.Address {
|
||||||
return []sdk.Address{msg.ValidatorAddr}
|
return []sdk.Address{msg.ValidatorAddr}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the bytes for the message signer to sign on
|
// get the bytes for the message signer to sign on
|
||||||
func (msg MsgDeclareCandidacy) GetSignBytes() []byte {
|
func (msg MsgCreateValidator) GetSignBytes() []byte {
|
||||||
return msgCdc.MustMarshalBinary(msg)
|
return msgCdc.MustMarshalBinary(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// quick validity check
|
// quick validity check
|
||||||
func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error {
|
func (msg MsgCreateValidator) ValidateBasic() sdk.Error {
|
||||||
if msg.ValidatorAddr == nil {
|
if msg.ValidatorAddr == nil {
|
||||||
return ErrValidatorEmpty(DefaultCodespace)
|
return ErrValidatorEmpty(DefaultCodespace)
|
||||||
}
|
}
|
||||||
|
@ -77,28 +68,28 @@ func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error {
|
||||||
|
|
||||||
//______________________________________________________________________
|
//______________________________________________________________________
|
||||||
|
|
||||||
// MsgEditCandidacy - struct for editing a validator
|
// MsgEditValidator - struct for editing a validator
|
||||||
type MsgEditCandidacy struct {
|
type MsgEditValidator struct {
|
||||||
Description
|
Description
|
||||||
ValidatorAddr sdk.Address `json:"address"`
|
ValidatorAddr sdk.Address `json:"address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMsgEditCandidacy(validatorAddr sdk.Address, description Description) MsgEditCandidacy {
|
func NewMsgEditValidator(validatorAddr sdk.Address, description Description) MsgEditValidator {
|
||||||
return MsgEditCandidacy{
|
return MsgEditValidator{
|
||||||
Description: description,
|
Description: description,
|
||||||
ValidatorAddr: validatorAddr,
|
ValidatorAddr: validatorAddr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint
|
//nolint
|
||||||
func (msg MsgEditCandidacy) Type() string { return MsgType } //TODO update "stake/msgeditcandidacy"
|
func (msg MsgEditValidator) Type() string { return MsgType }
|
||||||
func (msg MsgEditCandidacy) GetSigners() []sdk.Address {
|
func (msg MsgEditValidator) GetSigners() []sdk.Address {
|
||||||
return []sdk.Address{msg.ValidatorAddr}
|
return []sdk.Address{msg.ValidatorAddr}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the bytes for the message signer to sign on
|
// get the bytes for the message signer to sign on
|
||||||
func (msg MsgEditCandidacy) GetSignBytes() []byte {
|
func (msg MsgEditValidator) GetSignBytes() []byte {
|
||||||
b, err := json.Marshal(msg)
|
b, err := msgCdc.MarshalJSON(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -106,7 +97,7 @@ func (msg MsgEditCandidacy) GetSignBytes() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// quick validity check
|
// quick validity check
|
||||||
func (msg MsgEditCandidacy) ValidateBasic() sdk.Error {
|
func (msg MsgEditValidator) ValidateBasic() sdk.Error {
|
||||||
if msg.ValidatorAddr == nil {
|
if msg.ValidatorAddr == nil {
|
||||||
return ErrValidatorEmpty(DefaultCodespace)
|
return ErrValidatorEmpty(DefaultCodespace)
|
||||||
}
|
}
|
||||||
|
@ -121,8 +112,8 @@ func (msg MsgEditCandidacy) ValidateBasic() sdk.Error {
|
||||||
|
|
||||||
// MsgDelegate - struct for bonding transactions
|
// MsgDelegate - struct for bonding transactions
|
||||||
type MsgDelegate struct {
|
type MsgDelegate struct {
|
||||||
DelegatorAddr sdk.Address `json:"address"`
|
DelegatorAddr sdk.Address `json:"delegator_addr"`
|
||||||
ValidatorAddr sdk.Address `json:"address"`
|
ValidatorAddr sdk.Address `json:"validator_addr"`
|
||||||
Bond sdk.Coin `json:"bond"`
|
Bond sdk.Coin `json:"bond"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,14 +126,14 @@ func NewMsgDelegate(delegatorAddr, validatorAddr sdk.Address, bond sdk.Coin) Msg
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint
|
//nolint
|
||||||
func (msg MsgDelegate) Type() string { return MsgType } //TODO update "stake/msgeditcandidacy"
|
func (msg MsgDelegate) Type() string { return MsgType }
|
||||||
func (msg MsgDelegate) GetSigners() []sdk.Address {
|
func (msg MsgDelegate) GetSigners() []sdk.Address {
|
||||||
return []sdk.Address{msg.DelegatorAddr}
|
return []sdk.Address{msg.DelegatorAddr}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the bytes for the message signer to sign on
|
// get the bytes for the message signer to sign on
|
||||||
func (msg MsgDelegate) GetSignBytes() []byte {
|
func (msg MsgDelegate) GetSignBytes() []byte {
|
||||||
b, err := json.Marshal(msg)
|
b, err := msgCdc.MarshalJSON(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -170,8 +161,8 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error {
|
||||||
|
|
||||||
// MsgUnbond - struct for unbonding transactions
|
// MsgUnbond - struct for unbonding transactions
|
||||||
type MsgUnbond struct {
|
type MsgUnbond struct {
|
||||||
DelegatorAddr sdk.Address `json:"address"`
|
DelegatorAddr sdk.Address `json:"delegator_addr"`
|
||||||
ValidatorAddr sdk.Address `json:"address"`
|
ValidatorAddr sdk.Address `json:"validator_addr"`
|
||||||
Shares string `json:"shares"`
|
Shares string `json:"shares"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,12 +175,12 @@ func NewMsgUnbond(delegatorAddr, validatorAddr sdk.Address, shares string) MsgUn
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint
|
//nolint
|
||||||
func (msg MsgUnbond) Type() string { return MsgType } //TODO update "stake/msgeditcandidacy"
|
func (msg MsgUnbond) Type() string { return MsgType }
|
||||||
func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.DelegatorAddr} }
|
func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.DelegatorAddr} }
|
||||||
|
|
||||||
// get the bytes for the message signer to sign on
|
// get the bytes for the message signer to sign on
|
||||||
func (msg MsgUnbond) GetSignBytes() []byte {
|
func (msg MsgUnbond) GetSignBytes() []byte {
|
||||||
b, err := json.Marshal(msg)
|
b, err := msgCdc.MarshalJSON(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ var (
|
||||||
coinNegNotAtoms = sdk.Coin{"foo", -10000}
|
coinNegNotAtoms = sdk.Coin{"foo", -10000}
|
||||||
)
|
)
|
||||||
|
|
||||||
// test ValidateBasic for MsgDeclareCandidacy
|
// test ValidateBasic for MsgCreateValidator
|
||||||
func TestMsgDeclareCandidacy(t *testing.T) {
|
func TestMsgCreateValidator(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name, moniker, identity, website, details string
|
name, moniker, identity, website, details string
|
||||||
validatorAddr sdk.Address
|
validatorAddr sdk.Address
|
||||||
|
@ -40,7 +40,7 @@ func TestMsgDeclareCandidacy(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
|
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
|
||||||
msg := NewMsgDeclareCandidacy(tc.validatorAddr, tc.pubkey, tc.bond, description)
|
msg := NewMsgCreateValidator(tc.validatorAddr, tc.pubkey, tc.bond, description)
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -49,8 +49,8 @@ func TestMsgDeclareCandidacy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test ValidateBasic for MsgEditCandidacy
|
// test ValidateBasic for MsgEditValidator
|
||||||
func TestMsgEditCandidacy(t *testing.T) {
|
func TestMsgEditValidator(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name, moniker, identity, website, details string
|
name, moniker, identity, website, details string
|
||||||
validatorAddr sdk.Address
|
validatorAddr sdk.Address
|
||||||
|
@ -64,7 +64,7 @@ func TestMsgEditCandidacy(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
|
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
|
||||||
msg := NewMsgEditCandidacy(tc.validatorAddr, description)
|
msg := NewMsgEditValidator(tc.validatorAddr, description)
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,8 +139,8 @@ func TestMsgUnbond(t *testing.T) {
|
||||||
//tests := []struct {
|
//tests := []struct {
|
||||||
//tx sdk.Msg
|
//tx sdk.Msg
|
||||||
//}{
|
//}{
|
||||||
//{NewMsgDeclareCandidacy(addrs[0], pks[0], bond, Description{})},
|
//{NewMsgCreateValidator(addrs[0], pks[0], bond, Description{})},
|
||||||
//{NewMsgEditCandidacy(addrs[0], Description{})},
|
//{NewMsgEditValidator(addrs[0], Description{})},
|
||||||
//{NewMsgDelegate(addrs[0], addrs[1], bond)},
|
//{NewMsgDelegate(addrs[0], addrs[1], bond)},
|
||||||
//{NewMsgUnbond(addrs[0], addrs[1], strconv.Itoa(bondAmt))},
|
//{NewMsgUnbond(addrs[0], addrs[1], strconv.Itoa(bondAmt))},
|
||||||
//}
|
//}
|
||||||
|
|
|
@ -18,12 +18,13 @@ type Params struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Params) equal(p2 Params) bool {
|
func (p Params) equal(p2 Params) bool {
|
||||||
bz1 := cdcEmpty.MustMarshalBinary(&p)
|
bz1 := msgCdc.MustMarshalBinary(&p)
|
||||||
bz2 := cdcEmpty.MustMarshalBinary(&p2)
|
bz2 := msgCdc.MustMarshalBinary(&p2)
|
||||||
return bytes.Equal(bz1, bz2)
|
return bytes.Equal(bz1, bz2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultParams() Params {
|
// default params
|
||||||
|
func DefaultParams() Params {
|
||||||
return Params{
|
return Params{
|
||||||
InflationRateChange: sdk.NewRat(13, 100),
|
InflationRateChange: sdk.NewRat(13, 100),
|
||||||
InflationMax: sdk.NewRat(20, 100),
|
InflationMax: sdk.NewRat(20, 100),
|
||||||
|
|
|
@ -25,13 +25,13 @@ type Pool struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p Pool) equal(p2 Pool) bool {
|
func (p Pool) equal(p2 Pool) bool {
|
||||||
bz1 := cdcEmpty.MustMarshalBinary(&p)
|
bz1 := msgCdc.MustMarshalBinary(&p)
|
||||||
bz2 := cdcEmpty.MustMarshalBinary(&p2)
|
bz2 := msgCdc.MustMarshalBinary(&p2)
|
||||||
return bytes.Equal(bz1, bz2)
|
return bytes.Equal(bz1, bz2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial pool for testing
|
// initial pool for testing
|
||||||
func initialPool() Pool {
|
func InitialPool() Pool {
|
||||||
return Pool{
|
return Pool{
|
||||||
LooseUnbondedTokens: 0,
|
LooseUnbondedTokens: 0,
|
||||||
BondedTokens: 0,
|
BondedTokens: 0,
|
||||||
|
|
|
@ -44,8 +44,8 @@ func makeTestCodec() *wire.Codec {
|
||||||
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
|
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
|
||||||
cdc.RegisterConcrete(bank.MsgSend{}, "test/stake/Send", nil)
|
cdc.RegisterConcrete(bank.MsgSend{}, "test/stake/Send", nil)
|
||||||
cdc.RegisterConcrete(bank.MsgIssue{}, "test/stake/Issue", nil)
|
cdc.RegisterConcrete(bank.MsgIssue{}, "test/stake/Issue", nil)
|
||||||
cdc.RegisterConcrete(MsgDeclareCandidacy{}, "test/stake/DeclareCandidacy", nil)
|
cdc.RegisterConcrete(MsgCreateValidator{}, "test/stake/CreateValidator", nil)
|
||||||
cdc.RegisterConcrete(MsgEditCandidacy{}, "test/stake/EditCandidacy", nil)
|
cdc.RegisterConcrete(MsgEditValidator{}, "test/stake/EditValidator", nil)
|
||||||
cdc.RegisterConcrete(MsgUnbond{}, "test/stake/Unbond", nil)
|
cdc.RegisterConcrete(MsgUnbond{}, "test/stake/Unbond", nil)
|
||||||
|
|
||||||
// Register AppAccount
|
// Register AppAccount
|
||||||
|
@ -89,8 +89,8 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
|
||||||
)
|
)
|
||||||
ck := bank.NewKeeper(accountMapper)
|
ck := bank.NewKeeper(accountMapper)
|
||||||
keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace)
|
keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace)
|
||||||
keeper.setPool(ctx, initialPool())
|
keeper.setPool(ctx, InitialPool())
|
||||||
keeper.setNewParams(ctx, defaultParams())
|
keeper.setNewParams(ctx, DefaultParams())
|
||||||
|
|
||||||
// fill all the addresses with some coins
|
// fill all the addresses with some coins
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
|
@ -120,7 +120,7 @@ func testAddr(addr string, bech string) sdk.Address {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
bechexpected, err := sdk.Bech32CosmosifyAcc(res)
|
bechexpected, err := sdk.Bech32ifyAcc(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ func testAddr(addr string, bech string) sdk.Address {
|
||||||
panic("Bech encoding doesn't match reference")
|
panic("Bech encoding doesn't match reference")
|
||||||
}
|
}
|
||||||
|
|
||||||
bechres, err := sdk.GetAccAddressBech32Cosmos(bech)
|
bechres, err := sdk.GetAccAddressBech32(bech)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue