fixed merge conflicts
This commit is contained in:
commit
33a5e01264
|
@ -85,6 +85,22 @@ jobs:
|
|||
export PATH="$GOBIN:$PATH"
|
||||
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:
|
||||
<<: *defaults
|
||||
parallelism: 4
|
||||
|
@ -138,6 +154,9 @@ workflows:
|
|||
- lint:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_cli:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_unit:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
|
|
|
@ -4,3 +4,5 @@
|
|||
* [ ] Updated all code comments where relevant
|
||||
* [ ] Wrote tests
|
||||
* [ ] Updated CHANGELOG.md
|
||||
* [ ] Updated Basecoin / other examples
|
||||
* [ ] Squashed related commits and prefixed with PR number per [coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)
|
||||
|
|
|
@ -19,8 +19,11 @@ baseapp/data/*
|
|||
coverage.txt
|
||||
profile.out
|
||||
|
||||
### Vagrant ###
|
||||
# Vagrant
|
||||
.vagrant/
|
||||
*.box
|
||||
*.log
|
||||
vagrant
|
||||
|
||||
# Graphviz
|
||||
dependency-graph.png
|
58
CHANGELOG.md
58
CHANGELOG.md
|
@ -1,30 +1,18 @@
|
|||
# Changelog
|
||||
|
||||
## 0.18.1
|
||||
|
||||
BREAKING CHANGES
|
||||
|
||||
* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes:
|
||||
* StdTx (and its related stuff i.e. StdSignDoc, etc)
|
||||
* StdFee
|
||||
* StdSignature
|
||||
* Account interface
|
||||
* Related to this organization, I also:
|
||||
* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module)
|
||||
* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper
|
||||
* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature)
|
||||
* [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types
|
||||
* Switch to bech32cosmos on all human readable inputs and outputs
|
||||
FEATURES
|
||||
|
||||
BUG FIXES
|
||||
IMPROVEMENTS
|
||||
* export command now writes current validator set for Tendermint
|
||||
|
||||
* auto-sequencing transactions correctly
|
||||
* query sequence via account store
|
||||
* fixed duplicate pub_key in stake.Validator
|
||||
FIXES
|
||||
* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs
|
||||
|
||||
## 0.18.0
|
||||
|
||||
_TBD_
|
||||
_2018-06-05_
|
||||
|
||||
BREAKING CHANGES
|
||||
|
||||
|
@ -43,6 +31,20 @@ BREAKING CHANGES
|
|||
* Introduction of Unbonding fields, lowlevel logic throughout (not fully implemented with queue)
|
||||
* Introduction of PoolShares type within validators,
|
||||
replaces three rational fields (BondedShares, UnbondingShares, UnbondedShares
|
||||
* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes:
|
||||
* StdTx (and its related stuff i.e. StdSignDoc, etc)
|
||||
* StdFee
|
||||
* StdSignature
|
||||
* Account interface
|
||||
* Related to this organization, I also:
|
||||
* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module)
|
||||
* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper
|
||||
* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature)
|
||||
* [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types
|
||||
* [cli] rearranged commands under subcommands
|
||||
* [stake] remove Tick and add EndBlocker
|
||||
* Switch to bech32cosmos on all human readable inputs and outputs
|
||||
|
||||
|
||||
FEATURES
|
||||
|
||||
|
@ -56,14 +58,25 @@ FEATURES
|
|||
* [stake] Creation of a validator/delegation generics in `/types`
|
||||
* [stake] Helper Description of the store in x/stake/store.md
|
||||
* [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
|
||||
|
||||
|
||||
BUG FIXES
|
||||
|
||||
* Auto-sequencing now works correctly
|
||||
* [stake] staking delegator shares exchange rate now relative to equivalent-bonded-tokens the validator has instead of bonded tokens
|
||||
^ this is important for unbonded validators in the power store!
|
||||
* [cli] fixed cli-bash tests
|
||||
* [ci] added cli-bash tests
|
||||
* [basecoin] updated basecoin for stake and slashing
|
||||
* [docs] fixed references to old cli commands
|
||||
* [docs] Downgraded Swagger to v2 for downstream compatibility
|
||||
* auto-sequencing transactions correctly
|
||||
* query sequence via account store
|
||||
* fixed duplicate pub_key in stake.Validator
|
||||
* Auto-sequencing now works correctly
|
||||
|
||||
|
||||
|
||||
## 0.17.2
|
||||
|
||||
|
@ -87,7 +100,7 @@ FEATURES
|
|||
* [gaiacli] Support queries for candidates, delegator-bonds
|
||||
* [gaiad] Added `gaiad export` command to export current state to JSON
|
||||
* [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
|
||||
|
||||
|
@ -103,6 +116,7 @@ BUG FIXES
|
|||
|
||||
* Auto-sequencing now works correctly
|
||||
|
||||
|
||||
## 0.16.0 (May 14th, 2018)
|
||||
|
||||
BREAKING CHANGES
|
||||
|
@ -121,7 +135,7 @@ BREAKING CHANGES
|
|||
|
||||
FEATURES:
|
||||
|
||||
* Gaia stake commands include, DeclareCandidacy, EditCandidacy, Delegate, Unbond
|
||||
* Gaia stake commands include, CreateValidator, EditValidator, Delegate, Unbond
|
||||
* MountStoreWithDB without providing a custom store works.
|
||||
* Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI
|
||||
* 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
|
||||
|
||||
|
||||
## 0.15.1 (April 29, 2018)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* Update Tendermint to v0.19.1 (includes many rpc fixes)
|
||||
|
||||
|
||||
## 0.15.0 (April 29, 2018)
|
||||
|
||||
NOTE: v0.15.0 is a large breaking change that updates the encoding scheme to use
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
branch = "master"
|
||||
name = "github.com/btcsuite/btcd"
|
||||
packages = ["btcec"]
|
||||
revision = "1432d294a5b055c297457c25434efbf13384cc46"
|
||||
revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/cosmos/bech32cosmos"
|
||||
packages = ["go"]
|
||||
revision = "efca97cd8c0852c44d96dfdcc70565c306eddff0"
|
||||
name = "github.com/btcsuite/btcutil"
|
||||
packages = ["bech32"]
|
||||
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
|
@ -256,7 +256,7 @@
|
|||
"leveldb/table",
|
||||
"leveldb/util"
|
||||
]
|
||||
revision = "e6d6b529196422703d54ff5c40e79809ec2020b3"
|
||||
revision = "5d6fca44a948d2be89a9702de7717f0168403d3d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/abci"
|
||||
|
@ -267,8 +267,8 @@
|
|||
"server",
|
||||
"types"
|
||||
]
|
||||
revision = "78a8905690ef54f9d57e3b2b0ee7ad3a04ef3f1f"
|
||||
version = "v0.10.3"
|
||||
revision = "9af8b7a7c87478869f8c280ed9539470b8f470b4"
|
||||
version = "v0.11.0-rc4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -298,17 +298,14 @@
|
|||
revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19"
|
||||
version = "v0.6.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/go-wire"
|
||||
packages = ["."]
|
||||
revision = "fa721242b042ecd4c6ed1a934ee740db4f74e45c"
|
||||
version = "v0.7.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/iavl"
|
||||
packages = ["."]
|
||||
revision = "fd37a0fa3a7454423233bc3d5ea828f38e0af787"
|
||||
version = "v0.7.0"
|
||||
packages = [
|
||||
".",
|
||||
"sha256truncated"
|
||||
]
|
||||
revision = "c9206995e8f948e99927f5084a88a7e94ca256da"
|
||||
version = "v0.8.0-rc0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
|
@ -319,6 +316,9 @@
|
|||
"consensus",
|
||||
"consensus/types",
|
||||
"evidence",
|
||||
"libs/events",
|
||||
"libs/pubsub",
|
||||
"libs/pubsub/query",
|
||||
"lite",
|
||||
"lite/client",
|
||||
"lite/errors",
|
||||
|
@ -347,13 +347,15 @@
|
|||
"types/priv_validator",
|
||||
"version"
|
||||
]
|
||||
revision = "018e096748bafe1d2d1e69b909e4158f3b26f6b2"
|
||||
version = "v0.19.5-rc1"
|
||||
revision = "b5baab0238c9ec26e3b2d229b0243f9ff9220bdb"
|
||||
version = "v0.20.0-rc3"
|
||||
|
||||
[[projects]]
|
||||
branch = "develop"
|
||||
name = "github.com/tendermint/tmlibs"
|
||||
packages = [
|
||||
"autofile",
|
||||
"bech32",
|
||||
"cli",
|
||||
"cli/flags",
|
||||
"clist",
|
||||
|
@ -362,11 +364,9 @@
|
|||
"flowrate",
|
||||
"log",
|
||||
"merkle",
|
||||
"pubsub",
|
||||
"pubsub/query"
|
||||
"merkle/tmhash"
|
||||
]
|
||||
revision = "cc5f287c4798ffe88c04d02df219ecb6932080fd"
|
||||
version = "v0.8.3-rc0"
|
||||
revision = "44f1bdb0d55cc6527e38d0a7aab406e2580f56a4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -382,7 +382,7 @@
|
|||
"ripemd160",
|
||||
"salsa20/salsa"
|
||||
]
|
||||
revision = "1a580b3eff7814fc9b40602fd35256c63b50f491"
|
||||
revision = "5ba7f63082460102a45837dbd1827e10f9479ac0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -396,13 +396,13 @@
|
|||
"internal/timeseries",
|
||||
"trace"
|
||||
]
|
||||
revision = "57065200b4b034a1c8ad54ff77069408c2218ae6"
|
||||
revision = "1e491301e022f8f977054da4c2d852decd59571f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b"
|
||||
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
|
@ -463,6 +463,6 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "f0c6224dc5f30c1a7dea716d619665831ea0932b0eb9afc6ac897dbc459134fa"
|
||||
inputs-digest = "ccb2ab7644a38c2d0326280582f758256e37fc98c3ef0403581e3b85cff42188"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
22
Gopkg.toml
22
Gopkg.toml
|
@ -54,43 +54,33 @@
|
|||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/abci"
|
||||
version = "~0.10.3"
|
||||
version = "=0.11.0-rc4"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/go-crypto"
|
||||
version = "~0.6.2"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/go-wire"
|
||||
version = "0.7.3"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/go-amino"
|
||||
version = "~0.9.9"
|
||||
version = "=0.9.9"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/iavl"
|
||||
version = "~0.7.0"
|
||||
version = "0.8.0-rc0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
version = "0.19.5-rc1"
|
||||
version = "=0.20.0-rc3"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/tmlibs"
|
||||
version = "~0.8.3-rc0"
|
||||
|
||||
branch = "develop"
|
||||
|
||||
# this got updated and broke, so locked to an old working commit ...
|
||||
[[override]]
|
||||
name = "google.golang.org/genproto"
|
||||
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/cosmos/bech32cosmos"
|
||||
branch = "master"
|
||||
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
|
|
2
Makefile
2
Makefile
|
@ -70,7 +70,7 @@ get_vendor_deps:
|
|||
draw_deps:
|
||||
@# requires brew install graphviz or apt-get install graphviz
|
||||
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
|
||||
|
||||
|
||||
########################################
|
||||
|
|
|
@ -65,9 +65,10 @@ type BaseApp struct {
|
|||
// See methods setCheckState and setDeliverState.
|
||||
// .valUpdates accumulate in DeliverTx and are reset in BeginBlock.
|
||||
// QUESTION: should we put valUpdates in the deliverState.ctx?
|
||||
checkState *state // for CheckTx
|
||||
deliverState *state // for DeliverTx
|
||||
valUpdates []abci.Validator // cached validator changes from DeliverTx
|
||||
checkState *state // for CheckTx
|
||||
deliverState *state // for DeliverTx
|
||||
valUpdates []abci.Validator // cached validator changes from DeliverTx
|
||||
signedValidators []abci.SigningValidator // absent validators from begin block
|
||||
}
|
||||
|
||||
var _ abci.Application = (*BaseApp)(nil)
|
||||
|
@ -384,6 +385,8 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
|||
if app.beginBlocker != nil {
|
||||
res = app.beginBlocker(app.deliverState.ctx, req)
|
||||
}
|
||||
// set the signed validators for addition to context in deliverTx
|
||||
app.signedValidators = req.Validators
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -493,6 +496,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
|
|||
ctx = app.checkState.ctx.WithTxBytes(txBytes)
|
||||
} else {
|
||||
ctx = app.deliverState.ctx.WithTxBytes(txBytes)
|
||||
ctx = ctx.WithSigningValidators(app.signedValidators)
|
||||
}
|
||||
|
||||
// Simulate a DeliverTx for gas calculation
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package baseapp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
@ -12,6 +11,7 @@ import (
|
|||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -83,18 +83,36 @@ func TestLoadVersion(t *testing.T) {
|
|||
header := abci.Header{Height: 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
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.MountStoresIAVL(capKey)
|
||||
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||
err = app.LoadLatestVersion(capKey)
|
||||
assert.Nil(t, err)
|
||||
testLoadVersionHelper(t, app, int64(2), commitID2)
|
||||
|
||||
lastHeight = app.LastBlockHeight()
|
||||
lastID = app.LastCommitID()
|
||||
assert.Equal(t, int64(1), lastHeight)
|
||||
assert.Equal(t, commitID, lastID)
|
||||
// reload with LoadVersion, see if you can commit the same block and get
|
||||
// the same result
|
||||
app = NewBaseApp(name, nil, logger, db)
|
||||
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
|
||||
|
@ -206,11 +224,91 @@ func TestInitChainer(t *testing.T) {
|
|||
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
|
||||
// on the store within a block, and that the CheckTx state
|
||||
// gets reset to the latest Committed state during Commit
|
||||
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
|
||||
|
@ -224,30 +322,9 @@ func TestDeliverTx(t *testing.T) {
|
|||
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||
assert.Nil(t, err)
|
||||
|
||||
counter := 0
|
||||
txPerHeight := 2
|
||||
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 {
|
||||
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{}
|
||||
})
|
||||
app.Router().AddRoute(msgType, getStateCheckingHandler(t, capKey, txPerHeight, true))
|
||||
|
||||
tx := testUpdatePowerTx{} // doesn't matter
|
||||
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
|
||||
func TestTxGasLimits(t *testing.T) {
|
||||
logger := defaultLogger()
|
||||
|
@ -510,15 +608,20 @@ func TestValidatorChange(t *testing.T) {
|
|||
|
||||
// Assert that validator updates are correct.
|
||||
for _, val := range valSet {
|
||||
|
||||
pubkey, err := tmtypes.PB2TM.PubKey(val.PubKey)
|
||||
// Sanity
|
||||
assert.NotEqual(t, len(val.PubKey), 0)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Find matching update and splice it out.
|
||||
for j := 0; j < len(valUpdates); {
|
||||
for j := 0; j < len(valUpdates); j++ {
|
||||
valUpdate := valUpdates[j]
|
||||
|
||||
updatePubkey, err := tmtypes.PB2TM.PubKey(valUpdate.PubKey)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Matched.
|
||||
if bytes.Equal(valUpdate.PubKey, val.PubKey) {
|
||||
if updatePubkey.Equals(pubkey) {
|
||||
assert.Equal(t, valUpdate.Power, val.Power+1)
|
||||
if j < len(valUpdates)-1 {
|
||||
// Splice it out.
|
||||
|
@ -528,7 +631,6 @@ func TestValidatorChange(t *testing.T) {
|
|||
}
|
||||
|
||||
// Not matched.
|
||||
j++
|
||||
}
|
||||
}
|
||||
assert.Equal(t, len(valUpdates), 0, "Some validator updates were unexpected")
|
||||
|
@ -542,7 +644,7 @@ func randPower() int64 {
|
|||
|
||||
func makeVal(secret string) abci.Validator {
|
||||
return abci.Validator{
|
||||
PubKey: makePubKey(secret).Bytes(),
|
||||
PubKey: tmtypes.TM2PB.PubKey(makePubKey(secret)),
|
||||
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
|
||||
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()
|
||||
if err != nil {
|
||||
return res, err
|
||||
|
|
|
@ -102,12 +102,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// addOutput lets us json format the data
|
||||
type addOutput struct {
|
||||
Key keys.Info `json:"key"`
|
||||
Seed string `json:"seed"`
|
||||
}
|
||||
|
||||
func printCreate(info keys.Info, seed string) {
|
||||
output := viper.Get(cli.OutputFlag)
|
||||
switch output {
|
||||
|
@ -121,7 +115,10 @@ func printCreate(info keys.Info, seed string) {
|
|||
fmt.Println(seed)
|
||||
}
|
||||
case "json":
|
||||
out := addOutput{Key: info}
|
||||
out, err := Bech32KeyOutput(info)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !viper.GetBool(flagNoBackup) {
|
||||
out.Seed = seed
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
@ -54,9 +53,11 @@ func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
w.Write([]byte("[]"))
|
||||
return
|
||||
}
|
||||
keysOutput := make([]KeyOutput, len(infos))
|
||||
for i, info := range infos {
|
||||
keysOutput[i] = KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address().Bytes())}
|
||||
keysOutput, err := Bech32KeysOutput(infos)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
output, err := json.MarshalIndent(keysOutput, "", " ")
|
||||
if err != nil {
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/gorilla/mux"
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
|
||||
|
@ -51,7 +50,12 @@ func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
keyOutput := KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address())}
|
||||
keyOutput, err := Bech32KeyOutput(info)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
output, err := json.MarshalIndent(keyOutput, "", " ")
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
package keys
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
@ -48,35 +46,53 @@ func SetKeyBase(kb keys.Keybase) {
|
|||
|
||||
// used for outputting keys.Info over REST
|
||||
type KeyOutput struct {
|
||||
Name string `json:"name"`
|
||||
Address sdk.Address `json:"address"`
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
PubKey string `json:"pub_key"`
|
||||
Seed string `json:"seed,omitempty"`
|
||||
}
|
||||
|
||||
func NewKeyOutput(info keys.Info) KeyOutput {
|
||||
return KeyOutput{
|
||||
Name: info.Name,
|
||||
Address: sdk.Address(info.PubKey.Address().Bytes()),
|
||||
PubKey: info.PubKey,
|
||||
}
|
||||
}
|
||||
|
||||
func NewKeyOutputs(infos []keys.Info) []KeyOutput {
|
||||
// create a list of KeyOutput in bech32 format
|
||||
func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) {
|
||||
kos := make([]KeyOutput, len(infos))
|
||||
for i, info := range infos {
|
||||
kos[i] = NewKeyOutput(info)
|
||||
ko, err := Bech32KeyOutput(info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kos[i] = ko
|
||||
}
|
||||
return kos
|
||||
return kos, nil
|
||||
}
|
||||
|
||||
// create a KeyOutput in bech32 format
|
||||
func Bech32KeyOutput(info keys.Info) (KeyOutput, error) {
|
||||
bechAccount, err := sdk.Bech32ifyAcc(sdk.Address(info.PubKey.Address().Bytes()))
|
||||
if err != nil {
|
||||
return KeyOutput{}, err
|
||||
}
|
||||
bechPubKey, err := sdk.Bech32ifyAccPub(info.PubKey)
|
||||
if err != nil {
|
||||
return KeyOutput{}, err
|
||||
}
|
||||
return KeyOutput{
|
||||
Name: info.Name,
|
||||
Address: bechAccount,
|
||||
PubKey: bechPubKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func printInfo(info keys.Info) {
|
||||
ko := NewKeyOutput(info)
|
||||
ko, err := Bech32KeyOutput(info)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
switch viper.Get(cli.OutputFlag) {
|
||||
case "text":
|
||||
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
||||
printKeyOutput(ko)
|
||||
case "json":
|
||||
out, err := json.MarshalIndent(ko, "", "\t")
|
||||
out, err := MarshalJSON(ko)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -85,7 +101,10 @@ func printInfo(info keys.Info) {
|
|||
}
|
||||
|
||||
func printInfos(infos []keys.Info) {
|
||||
kos := NewKeyOutputs(infos)
|
||||
kos, err := Bech32KeysOutput(infos)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
switch viper.Get(cli.OutputFlag) {
|
||||
case "text":
|
||||
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
||||
|
@ -93,7 +112,7 @@ func printInfos(infos []keys.Info) {
|
|||
printKeyOutput(ko)
|
||||
}
|
||||
case "json":
|
||||
out, err := json.MarshalIndent(kos, "", "\t")
|
||||
out, err := MarshalJSON(kos)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -102,13 +121,5 @@ func printInfos(infos []keys.Info) {
|
|||
}
|
||||
|
||||
func printKeyOutput(ko KeyOutput) {
|
||||
bechAccount, err := sdk.Bech32CosmosifyAcc(ko.Address)
|
||||
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)
|
||||
fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package lcd
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
cryptoKeys "github.com/tendermint/go-crypto/keys"
|
||||
tmcfg "github.com/tendermint/tendermint/config"
|
||||
nm "github.com/tendermint/tendermint/node"
|
||||
|
@ -31,21 +33,30 @@ import (
|
|||
|
||||
client "github.com/cosmos/cosmos-sdk/client"
|
||||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
bapp "github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
||||
btypes "github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
tests "github.com/cosmos/cosmos-sdk/tests"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||
)
|
||||
|
||||
var (
|
||||
coinDenom = "mycoin"
|
||||
coinDenom = "steak"
|
||||
coinAmount = int64(10000000)
|
||||
|
||||
validatorAddr1Hx = ""
|
||||
validatorAddr2Hx = ""
|
||||
validatorAddr1 = ""
|
||||
validatorAddr2 = ""
|
||||
|
||||
// XXX bad globals
|
||||
name = "test"
|
||||
password = "0123456789"
|
||||
port string // XXX: but it's the int ...
|
||||
port string
|
||||
seed string
|
||||
sendAddr string
|
||||
)
|
||||
|
@ -92,13 +103,13 @@ func TestKeys(t *testing.T) {
|
|||
err = cdc.UnmarshalJSON([]byte(body), &m)
|
||||
require.Nil(t, err)
|
||||
|
||||
sendAddrAcc, _ := sdk.GetAccAddressHex(sendAddr)
|
||||
addrAcc, _ := sdk.GetAccAddressHex(addr)
|
||||
addrBech32, _ := sdk.Bech32ifyAcc(addrAcc)
|
||||
|
||||
assert.Equal(t, m[0].Name, name, "Did not serve keys name correctly")
|
||||
assert.Equal(t, m[0].Address, sendAddrAcc, "Did not serve keys Address correctly")
|
||||
assert.Equal(t, m[1].Name, newName, "Did not serve keys name correctly")
|
||||
assert.Equal(t, m[1].Address, addrAcc, "Did not serve keys Address correctly")
|
||||
assert.Equal(t, name, m[0].Name, "Did not serve keys name correctly")
|
||||
assert.Equal(t, sendAddr, m[0].Address, "Did not serve keys Address correctly")
|
||||
assert.Equal(t, newName, m[1].Name, "Did not serve keys name correctly")
|
||||
assert.Equal(t, addrBech32, m[1].Address, "Did not serve keys Address correctly")
|
||||
|
||||
// select key
|
||||
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
|
||||
|
@ -109,7 +120,7 @@ func TestKeys(t *testing.T) {
|
|||
require.Nil(t, err)
|
||||
|
||||
assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
|
||||
assert.Equal(t, addrAcc, m2.Address, "Did not serve keys Address correctly")
|
||||
assert.Equal(t, addrBech32, m2.Address, "Did not serve keys Address correctly")
|
||||
|
||||
// update key
|
||||
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) {
|
||||
|
||||
var resultVals ctypes.ResultValidators
|
||||
var resultVals rpc.ResultValidatorsOutput
|
||||
|
||||
res, body := request(t, port, "GET", "/validatorsets/latest", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
@ -199,7 +210,10 @@ func TestValidators(t *testing.T) {
|
|||
err := cdc.UnmarshalJSON([]byte(body), &resultVals)
|
||||
require.Nil(t, err, "Couldn't parse validatorset")
|
||||
|
||||
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals)
|
||||
assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
|
||||
|
||||
assert.Contains(t, resultVals.Validators[0].Address, "cosmosvaladdr")
|
||||
assert.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub")
|
||||
|
||||
// --
|
||||
|
||||
|
@ -209,7 +223,7 @@ func TestValidators(t *testing.T) {
|
|||
err = cdc.UnmarshalJSON([]byte(body), &resultVals)
|
||||
require.Nil(t, err, "Couldn't parse validatorset")
|
||||
|
||||
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals)
|
||||
assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
|
||||
|
||||
// --
|
||||
|
||||
|
@ -218,9 +232,11 @@ func TestValidators(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCoinSend(t *testing.T) {
|
||||
bz, _ := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6")
|
||||
someFakeAddr, _ := sdk.Bech32ifyAcc(bz)
|
||||
|
||||
// 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)
|
||||
|
||||
acc := getAccount(t, sendAddr)
|
||||
|
@ -309,6 +325,62 @@ func TestTxs(t *testing.T) {
|
|||
// 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
|
||||
|
||||
|
@ -324,26 +396,18 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
|||
if err != nil {
|
||||
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.Consensus.TimeoutCommit = 1000
|
||||
config.Consensus.SkipTimeoutCommit = false
|
||||
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
// logger = log.NewFilter(logger, log.AllowError())
|
||||
logger = log.NewFilter(logger, log.AllowError())
|
||||
privValidatorFile := config.PrivValidatorFile()
|
||||
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
|
||||
db := dbm.NewMemDB()
|
||||
app := bapp.NewBasecoinApp(logger, db)
|
||||
cdc = bapp.MakeCodec() // XXX
|
||||
app := gapp.NewGaiaApp(logger, db)
|
||||
cdc = gapp.MakeCodec() // XXX
|
||||
|
||||
genesisFile := config.GenesisFile()
|
||||
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
||||
|
@ -351,25 +415,63 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
coins := sdk.Coins{{coinDenom, coinAmount}}
|
||||
appState := map[string]interface{}{
|
||||
"accounts": []*btypes.GenesisAccount{
|
||||
{
|
||||
Name: "tester",
|
||||
Address: pubKey.Address(),
|
||||
Coins: coins,
|
||||
},
|
||||
genDoc.Validators = append(genDoc.Validators,
|
||||
tmtypes.GenesisValidator{
|
||||
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
|
||||
Power: 1,
|
||||
Name: "val",
|
||||
},
|
||||
}
|
||||
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 {
|
||||
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
|
||||
port = fmt.Sprintf("%d", 17377) // XXX
|
||||
listenAddr := fmt.Sprintf("tcp://localhost:%s", port) // XXX
|
||||
var listenAddr string
|
||||
listenAddr, port, err = server.FreeTCPAddr()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// XXX: need to set this so LCD knows the tendermint node address!
|
||||
viper.Set(client.FlagNode, config.RPC.ListenAddress)
|
||||
|
@ -379,7 +481,7 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
lcd, err := startLCD(logger, listenAddr)
|
||||
lcd, err := startLCD(logger, listenAddr, cdc)
|
||||
if err != nil {
|
||||
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!
|
||||
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)
|
||||
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()
|
||||
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
||||
require.Nil(t, err)
|
||||
receiveAddr = receiveInfo.PubKey.Address().String()
|
||||
receiveAddr, _ = sdk.Bech32ifyAcc(receiveInfo.PubKey.Address())
|
||||
|
||||
acc := getAccount(t, sendAddr)
|
||||
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) {
|
||||
|
||||
// create receive address
|
||||
kb := client.MockKeyBase()
|
||||
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
||||
require.Nil(t, err)
|
||||
receiveAddr := receiveInfo.PubKey.Address().String()
|
||||
receiveAddr, _ := sdk.Bech32ifyAcc(receiveInfo.PubKey.Address())
|
||||
|
||||
// get the account to get the sequence
|
||||
acc := getAccount(t, sendAddr)
|
||||
|
@ -494,3 +595,81 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad
|
|||
|
||||
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"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||
ibc "github.com/cosmos/cosmos-sdk/x/ibc/client/rest"
|
||||
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -55,6 +56,7 @@ func startRESTServerFn(cdc *wire.Codec) func(cmd *cobra.Command, args []string)
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("REST server started")
|
||||
|
||||
// Wait forever and cleanup
|
||||
cmn.TrapSignal(func() {
|
||||
|
@ -83,5 +85,6 @@ func createHandler(cdc *wire.Codec) http.Handler {
|
|||
auth.RegisterRoutes(ctx, r, cdc, "acc")
|
||||
bank.RegisterRoutes(ctx, r, cdc, kb)
|
||||
ibc.RegisterRoutes(ctx, r, cdc, kb)
|
||||
stake.RegisterRoutes(ctx, r, cdc, kb)
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ const (
|
|||
flagSelect = "select"
|
||||
)
|
||||
|
||||
func blockCommand() *cobra.Command {
|
||||
//BlockCommand returns the verified block data for a given heights
|
||||
func BlockCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "block [height]",
|
||||
Short: "Get verified data for a the block at given height",
|
||||
|
|
|
@ -26,8 +26,6 @@ func AddCommands(cmd *cobra.Command) {
|
|||
cmd.AddCommand(
|
||||
initClientCommand(),
|
||||
statusCommand(),
|
||||
blockCommand(),
|
||||
validatorCommand(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,14 +10,17 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// TODO these next two functions feel kinda hacky based on their placement
|
||||
|
||||
func validatorCommand() *cobra.Command {
|
||||
//ValidatorCommand returns the validator set for a given height
|
||||
func ValidatorCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "validatorset [height]",
|
||||
Short: "Get the full validator set at given height",
|
||||
Use: "validator-set [height]",
|
||||
Short: "Get the full tendermint validator set at given height",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: printValidators,
|
||||
}
|
||||
|
@ -27,6 +30,38 @@ func validatorCommand() *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
// Validator output in bech32 format
|
||||
type ValidatorOutput struct {
|
||||
Address string `json:"address"` // in bech32
|
||||
PubKey string `json:"pub_key"` // in bech32
|
||||
Accum int64 `json:"accum"`
|
||||
VotingPower int64 `json:"voting_power"`
|
||||
}
|
||||
|
||||
// Validators at a certain height output in bech32 format
|
||||
type ResultValidatorsOutput struct {
|
||||
BlockHeight int64 `json:"block_height"`
|
||||
Validators []ValidatorOutput `json:"validators"`
|
||||
}
|
||||
|
||||
func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) {
|
||||
bechAddress, err := sdk.Bech32ifyVal(validator.Address)
|
||||
if err != nil {
|
||||
return ValidatorOutput{}, err
|
||||
}
|
||||
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
|
||||
if err != nil {
|
||||
return ValidatorOutput{}, err
|
||||
}
|
||||
|
||||
return ValidatorOutput{
|
||||
Address: bechAddress,
|
||||
PubKey: bechValPubkey,
|
||||
Accum: validator.Accum,
|
||||
VotingPower: validator.VotingPower,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
|
||||
// get the node
|
||||
node, err := ctx.GetNode()
|
||||
|
@ -34,12 +69,23 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
res, err := node.Validators(height)
|
||||
validatorsRes, err := node.Validators(height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
output, err := cdc.MarshalJSON(res)
|
||||
outputValidatorsRes := ResultValidatorsOutput{
|
||||
BlockHeight: validatorsRes.BlockHeight,
|
||||
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
|
||||
}
|
||||
for i := 0; i < len(validatorsRes.Validators); i++ {
|
||||
outputValidatorsRes.Validators[i], err = bech32ValidatorOutput(validatorsRes.Validators[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
output, err := cdc.MarshalJSON(outputValidatorsRes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -95,6 +141,7 @@ func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
|
|||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"os"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -15,6 +16,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
)
|
||||
|
||||
|
@ -34,10 +36,11 @@ type GaiaApp struct {
|
|||
cdc *wire.Codec
|
||||
|
||||
// keys to access the substores
|
||||
keyMain *sdk.KVStoreKey
|
||||
keyAccount *sdk.KVStoreKey
|
||||
keyIBC *sdk.KVStoreKey
|
||||
keyStake *sdk.KVStoreKey
|
||||
keyMain *sdk.KVStoreKey
|
||||
keyAccount *sdk.KVStoreKey
|
||||
keyIBC *sdk.KVStoreKey
|
||||
keyStake *sdk.KVStoreKey
|
||||
keySlashing *sdk.KVStoreKey
|
||||
|
||||
// Manage getting and setting accounts
|
||||
accountMapper auth.AccountMapper
|
||||
|
@ -45,6 +48,7 @@ type GaiaApp struct {
|
|||
coinKeeper bank.Keeper
|
||||
ibcMapper ibc.Mapper
|
||||
stakeKeeper stake.Keeper
|
||||
slashingKeeper slashing.Keeper
|
||||
}
|
||||
|
||||
func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
||||
|
@ -52,12 +56,13 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
|||
|
||||
// create your application object
|
||||
var app = &GaiaApp{
|
||||
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
|
||||
cdc: cdc,
|
||||
keyMain: sdk.NewKVStoreKey("main"),
|
||||
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||
keyIBC: sdk.NewKVStoreKey("ibc"),
|
||||
keyStake: sdk.NewKVStoreKey("stake"),
|
||||
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
|
||||
cdc: cdc,
|
||||
keyMain: sdk.NewKVStoreKey("main"),
|
||||
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||
keyIBC: sdk.NewKVStoreKey("ibc"),
|
||||
keyStake: sdk.NewKVStoreKey("stake"),
|
||||
keySlashing: sdk.NewKVStoreKey("slashing"),
|
||||
}
|
||||
|
||||
// define the accountMapper
|
||||
|
@ -71,6 +76,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
|||
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
|
||||
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
|
||||
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace))
|
||||
|
||||
// register message routes
|
||||
app.Router().
|
||||
|
@ -80,9 +86,10 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
|||
|
||||
// initialize BaseApp
|
||||
app.SetInitChainer(app.initChainer)
|
||||
app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper))
|
||||
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.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing)
|
||||
err := app.LoadLatestVersion(app.keyMain)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
|
@ -97,15 +104,35 @@ func MakeCodec() *wire.Codec {
|
|||
ibc.RegisterWire(cdc)
|
||||
bank.RegisterWire(cdc)
|
||||
stake.RegisterWire(cdc)
|
||||
slashing.RegisterWire(cdc)
|
||||
auth.RegisterWire(cdc)
|
||||
sdk.RegisterWire(cdc)
|
||||
wire.RegisterCrypto(cdc)
|
||||
return cdc
|
||||
}
|
||||
|
||||
// application updates every end block
|
||||
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||
tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper)
|
||||
|
||||
return abci.ResponseBeginBlock{
|
||||
Tags: tags.ToKVPairs(),
|
||||
}
|
||||
}
|
||||
|
||||
// application updates every end block
|
||||
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
|
||||
|
||||
return abci.ResponseEndBlock{
|
||||
ValidatorUpdates: validatorUpdates,
|
||||
}
|
||||
}
|
||||
|
||||
// custom logic for gaia initialization
|
||||
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
stateJSON := req.AppStateBytes
|
||||
// TODO is this now the whole genesis file?
|
||||
|
||||
var genesisState 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{}
|
||||
}
|
||||
|
||||
// export the state of gaia for a genesis f
|
||||
func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
||||
// export the state of gaia for a genesis file
|
||||
func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||
ctx := app.NewContext(true, abci.Header{})
|
||||
|
||||
// iterate to get the accounts
|
||||
|
@ -143,5 +170,10 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
|||
Accounts: accounts,
|
||||
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
|
||||
}
|
||||
return wire.MarshalJSONIndent(app.cdc, genState)
|
||||
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
validators = stake.WriteValidators(ctx, app.stakeKeeper)
|
||||
return appState, validators, nil
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
@ -115,7 +114,7 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
|||
|
||||
// Initialize the chain
|
||||
vals := []abci.Validator{}
|
||||
gapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
gapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||
gapp.Commit()
|
||||
|
||||
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) {
|
||||
logger, dbs := loggerAndDB()
|
||||
gapp := NewGaiaApp(logger, dbs)
|
||||
|
@ -178,7 +153,7 @@ func TestGenesis(t *testing.T) {
|
|||
}
|
||||
|
||||
err = setGenesis(gapp, baseAcc)
|
||||
assert.Nil(t, err)
|
||||
require.Nil(t, err)
|
||||
|
||||
// A checkTx context
|
||||
ctx := gapp.BaseApp.NewContext(true, abci.Header{})
|
||||
|
@ -394,13 +369,13 @@ func TestStakeMsgs(t *testing.T) {
|
|||
require.Equal(t, acc1, res1)
|
||||
require.Equal(t, acc2, res2)
|
||||
|
||||
// Declare Candidacy
|
||||
// Create Validator
|
||||
|
||||
description := stake.NewDescription("foo_moniker", "", "", "")
|
||||
declareCandidacyMsg := stake.NewMsgDeclareCandidacy(
|
||||
createValidatorMsg := stake.NewMsgCreateValidator(
|
||||
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{})
|
||||
res1 = gapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||
|
@ -415,13 +390,13 @@ func TestStakeMsgs(t *testing.T) {
|
|||
bond, found := gapp.stakeKeeper.GetDelegation(ctxDeliver, addr1, addr1)
|
||||
require.True(sdk.RatEq(t, sdk.NewRat(10), bond.Shares))
|
||||
|
||||
// Edit Candidacy
|
||||
// Edit Validator
|
||||
|
||||
description = stake.NewDescription("bar_moniker", "", "", "")
|
||||
editCandidacyMsg := stake.NewMsgEditCandidacy(
|
||||
editValidatorMsg := stake.NewMsgEditValidator(
|
||||
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)
|
||||
require.True(t, found)
|
||||
|
@ -455,6 +430,42 @@ func TestStakeMsgs(t *testing.T) {
|
|||
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) {
|
||||
|
|
|
@ -65,7 +65,7 @@ func GaiaAppInit() server.AppInit {
|
|||
fsAppGenState := 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,
|
||||
"home directory for the client, used for key generation")
|
||||
fsAppGenTx.Bool(flagOWK, false, "overwrite the accounts created")
|
||||
|
@ -74,7 +74,7 @@ func GaiaAppInit() server.AppInit {
|
|||
FlagsAppGenState: fsAppGenState,
|
||||
FlagsAppGenTx: fsAppGenTx,
|
||||
AppGenTx: GaiaAppGenTx,
|
||||
AppGenState: GaiaAppGenState,
|
||||
AppGenState: GaiaAppGenStateJSON,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,19 +85,35 @@ type GaiaGenTx struct {
|
|||
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) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
|
||||
var addr sdk.Address
|
||||
var secret string
|
||||
clientRoot := viper.GetString(flagClientHome)
|
||||
overwrite := viper.GetBool(flagOWK)
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
gaiaGenTx := GaiaGenTx{
|
||||
|
@ -111,13 +127,6 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
|||
}
|
||||
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{
|
||||
PubKey: pk,
|
||||
Power: freeFermionVal,
|
||||
|
@ -127,7 +136,7 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
|||
|
||||
// Create the core parameters for genesis initialization for gaia
|
||||
// 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 {
|
||||
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
|
||||
genesisState := GenesisState{
|
||||
genesisState = GenesisState{
|
||||
Accounts: genaccs,
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -30,46 +30,44 @@ func TestGaiaCLISend(t *testing.T) {
|
|||
executeWrite(t, "gaiacli keys add bar", pass)
|
||||
|
||||
// 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)
|
||||
|
||||
// start gaiad server
|
||||
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
||||
defer cmd.Process.Kill()
|
||||
proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
||||
defer proc.Stop(false)
|
||||
tests.WaitForStart(port)
|
||||
|
||||
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")
|
||||
barCech, err := sdk.Bech32ifyAcc(barAddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
fooBech, err := sdk.Bech32CosmosifyAcc(fooAddr)
|
||||
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))
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
|
||||
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)
|
||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass)
|
||||
time.Sleep(time.Second * 2) // waiting for some blocks to pass
|
||||
|
||||
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"))
|
||||
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"))
|
||||
|
||||
// test autosequencing
|
||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barAddr), pass)
|
||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass)
|
||||
time.Sleep(time.Second * 2) // waiting for some blocks to pass
|
||||
|
||||
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"))
|
||||
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"))
|
||||
}
|
||||
|
||||
func TestGaiaCLIDeclareCandidacy(t *testing.T) {
|
||||
func TestGaiaCLICreateValidator(t *testing.T) {
|
||||
|
||||
tests.ExecuteT(t, "gaiad unsafe_reset_all")
|
||||
pass := "1234567890"
|
||||
|
@ -79,95 +77,79 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) {
|
|||
executeWrite(t, "gaiacli keys add bar", pass)
|
||||
|
||||
// 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)
|
||||
|
||||
// start gaiad server
|
||||
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
||||
defer cmd.Process.Kill()
|
||||
proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
||||
defer proc.Stop(false)
|
||||
tests.WaitForStart(port)
|
||||
|
||||
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)
|
||||
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)
|
||||
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
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooBech, flags))
|
||||
assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak"))
|
||||
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"))
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
|
||||
assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak"))
|
||||
|
||||
// declare candidacy
|
||||
declStr := fmt.Sprintf("gaiacli create-validator %v", flags)
|
||||
declStr += fmt.Sprintf(" --name=%v", "bar")
|
||||
declStr += fmt.Sprintf(" --validator-address=%v", bechVal)
|
||||
declStr += fmt.Sprintf(" --amount=%v", "3steak")
|
||||
declStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
||||
fmt.Printf("debug declStr: %v\n", declStr)
|
||||
executeWrite(t, declStr, pass)
|
||||
time.Sleep(time.Second) // waiting for some blocks to pass
|
||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
|
||||
assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("steak"))
|
||||
candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr))
|
||||
assert.Equal(t, candidate.Owner.String(), barAddr)
|
||||
assert.Equal(t, int64(3), candidate.PoolShares)
|
||||
// create validator
|
||||
cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags)
|
||||
cvStr += fmt.Sprintf(" --name=%v", "bar")
|
||||
cvStr += fmt.Sprintf(" --address-validator=%v", barCech)
|
||||
cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey)
|
||||
cvStr += fmt.Sprintf(" --amount=%v", "2steak")
|
||||
cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
||||
|
||||
executeWrite(t, cvStr, pass)
|
||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
|
||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
|
||||
|
||||
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
|
||||
//unbondStr := fmt.Sprintf("gaiacli unbond %v", flags)
|
||||
//unbondStr += fmt.Sprintf(" --name=%v", "bar")
|
||||
//unbondStr += fmt.Sprintf(" --address-candidate=%v", barAddr)
|
||||
//unbondStr += fmt.Sprintf(" --address-delegator=%v", barAddr)
|
||||
//unbondStr += fmt.Sprintf(" --shares=%v", "1")
|
||||
//unbondStr += fmt.Sprintf(" --sequence=%v", "1")
|
||||
//fmt.Printf("debug unbondStr: %v\n", unbondStr)
|
||||
//executeWrite(t, unbondStr, pass)
|
||||
//time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
//barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
|
||||
//assert.Equal(t, int64(99998), barAcc.GetCoins().AmountOf("steak"))
|
||||
//candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr))
|
||||
//assert.Equal(t, int64(2), candidate.BondedShares.Evaluate())
|
||||
unbondStr := fmt.Sprintf("gaiacli stake unbond %v", flags)
|
||||
unbondStr += fmt.Sprintf(" --name=%v", "bar")
|
||||
unbondStr += fmt.Sprintf(" --address-validator=%v", barCech)
|
||||
unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech)
|
||||
unbondStr += fmt.Sprintf(" --shares=%v", "1")
|
||||
unbondStr += fmt.Sprintf(" --sequence=%v", "1")
|
||||
t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr))
|
||||
|
||||
executeWrite(t, unbondStr, pass)
|
||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
|
||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||
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) {
|
||||
cmd, wc, _ := tests.GoExecuteT(t, cmdStr)
|
||||
proc := tests.GoExecuteT(t, cmdStr)
|
||||
|
||||
for _, write := range writes {
|
||||
_, err := wc.Write([]byte(write + "\n"))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
_, err := proc.StdinPipe.Write([]byte(write + "\n"))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
fmt.Printf("debug waiting cmdStr: %v\n", cmdStr)
|
||||
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))
|
||||
proc.Wait()
|
||||
}
|
||||
|
||||
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)
|
||||
var ko keys.KeyOutput
|
||||
keys.UnmarshalJSON([]byte(out), &ko)
|
||||
return ko.Address, ko.PubKey
|
||||
|
||||
address, err := sdk.GetAccAddressBech32(ko.Address)
|
||||
require.NoError(t, err)
|
||||
|
||||
pk, err := sdk.GetAccPubKeyBech32(ko.PubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
return address, pk
|
||||
}
|
||||
|
||||
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
||||
|
@ -204,11 +193,11 @@ func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
|||
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)
|
||||
var candidate stake.Validator
|
||||
var validator stake.Validator
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &candidate)
|
||||
require.NoError(t, err, "out %v, err %v", out, err)
|
||||
return candidate
|
||||
err := cdc.UnmarshalJSON([]byte(out), &validator)
|
||||
require.NoError(t, err, "out %v\n, err %v", out, err)
|
||||
return validator
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/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"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
|
@ -35,36 +36,83 @@ func main() {
|
|||
// the below functions and eliminate global vars, like we do
|
||||
// with the cdc
|
||||
|
||||
// add standard rpc, and tx commands
|
||||
// add standard rpc commands
|
||||
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(
|
||||
advancedCmd,
|
||||
client.LineBreak,
|
||||
)
|
||||
|
||||
//Add stake commands
|
||||
stakeCmd := &cobra.Command{
|
||||
Use: "stake",
|
||||
Short: "Stake and validation subcommands",
|
||||
}
|
||||
stakeCmd.AddCommand(
|
||||
client.GetCommands(
|
||||
authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)),
|
||||
stakecmd.GetCmdQueryValidator("stake", cdc),
|
||||
stakecmd.GetCmdQueryValidators("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegation("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(
|
||||
client.PostCommands(
|
||||
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
|
||||
rootCmd.AddCommand(
|
||||
client.LineBreak,
|
||||
lcd.ServeCommand(cdc),
|
||||
keys.Commands(),
|
||||
client.LineBreak,
|
||||
version.VersionCmd,
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -17,6 +18,7 @@ import (
|
|||
func main() {
|
||||
cdc := app.MakeCodec()
|
||||
ctx := server.NewDefaultContext()
|
||||
cobra.EnableCommandSorting = false
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "gaiad",
|
||||
Short: "Gaia Daemon (server)",
|
||||
|
@ -25,7 +27,7 @@ func main() {
|
|||
|
||||
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
|
||||
server.ConstructAppCreator(newApp, "gaia"),
|
||||
server.ConstructAppExporter(exportAppState, "gaia"))
|
||||
server.ConstructAppExporter(exportAppStateAndTMValidators, "gaia"))
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
||||
|
@ -36,7 +38,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
|||
return app.NewGaiaApp(logger, db)
|
||||
}
|
||||
|
||||
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
gapp := app.NewGaiaApp(logger, db)
|
||||
return gapp.ExportAppStateJSON()
|
||||
return gapp.ExportAppStateAndValidators()
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ swagger: '2.0'
|
|||
info:
|
||||
version: '1.1.0'
|
||||
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:
|
||||
kms:
|
||||
type: basic
|
||||
|
@ -58,7 +58,7 @@ paths:
|
|||
responses:
|
||||
200:
|
||||
description: '"true" or "false"'
|
||||
|
||||
|
||||
/keys:
|
||||
get:
|
||||
summary: List of accounts stored locally
|
||||
|
@ -102,7 +102,7 @@ paths:
|
|||
- application/json
|
||||
responses:
|
||||
200:
|
||||
description: 12 word Seed
|
||||
description: 16 word Seed
|
||||
schema:
|
||||
type: string
|
||||
/keys/{name}:
|
||||
|
@ -199,12 +199,12 @@ paths:
|
|||
# description: Tx was send and will probably be added to the next block
|
||||
# 400:
|
||||
# description: The Tx was malformated
|
||||
|
||||
|
||||
/accounts/{address}:
|
||||
parameters:
|
||||
- in: path
|
||||
name: address
|
||||
description: Account address
|
||||
description: Account address in bech32 format
|
||||
required: true
|
||||
type: string
|
||||
get:
|
||||
|
@ -222,7 +222,7 @@ paths:
|
|||
parameters:
|
||||
- in: path
|
||||
name: address
|
||||
description: Account address
|
||||
description: Account address in bech32 format
|
||||
required: true
|
||||
type: string
|
||||
post:
|
||||
|
@ -255,18 +255,6 @@ paths:
|
|||
description: Tx was send and will probably be added to the next block
|
||||
400:
|
||||
description: The Tx was malformated
|
||||
/accounts/{address}/nonce:
|
||||
parameters:
|
||||
- in: path
|
||||
name: address
|
||||
description: Account address
|
||||
required: true
|
||||
type: string
|
||||
get:
|
||||
summary: Get the nonce for a certain account
|
||||
responses:
|
||||
200:
|
||||
description: Plaintext nonce i.e. "4" defaults to "0"
|
||||
/blocks/latest:
|
||||
get:
|
||||
summary: Get the latest block
|
||||
|
@ -304,9 +292,14 @@ paths:
|
|||
200:
|
||||
description: The validator set at the latest block height
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Delegate"
|
||||
type: object
|
||||
properties:
|
||||
block_height:
|
||||
type: number
|
||||
validators:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Validator"
|
||||
/validatorsets/{height}:
|
||||
parameters:
|
||||
- in: path
|
||||
|
@ -322,9 +315,14 @@ paths:
|
|||
200:
|
||||
description: The validator set at a specific block height
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Delegate"
|
||||
type: object
|
||||
properties:
|
||||
block_height:
|
||||
type: number
|
||||
validators:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/definitions/Validator"
|
||||
404:
|
||||
description: Block at height not available
|
||||
# /txs:
|
||||
|
@ -545,11 +543,24 @@ paths:
|
|||
# description: Tx was send and will probably be added to the next block
|
||||
# 400:
|
||||
# description: The Tx was malformated
|
||||
|
||||
|
||||
definitions:
|
||||
Address:
|
||||
type: string
|
||||
example: DF096FDE8D380FA5B2AD20DB2962C82DDEA1ED9B
|
||||
description: bech32 encoded addres
|
||||
example: cosmosaccaddr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
||||
ValidatorAddress:
|
||||
type: string
|
||||
description: bech32 encoded addres
|
||||
example: cosmosvaladdr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
||||
PubKey:
|
||||
type: string
|
||||
description: bech32 encoded public key
|
||||
example: cosmosaccpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
||||
ValidatorPubKey:
|
||||
type: string
|
||||
description: bech32 encoded public key
|
||||
example: cosmosvalpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
||||
Coins:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -630,7 +641,7 @@ definitions:
|
|||
Sig:
|
||||
type: string
|
||||
default: ''
|
||||
Pubkey:
|
||||
Pubkey:
|
||||
type: string
|
||||
default: ''
|
||||
TxSigned:
|
||||
|
@ -652,16 +663,6 @@ definitions:
|
|||
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
||||
Pubkey:
|
||||
$ref: "#/definitions/PubKey"
|
||||
PubKey:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- ed25519
|
||||
data:
|
||||
type: string
|
||||
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
||||
Account:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -704,17 +705,17 @@ definitions:
|
|||
properties:
|
||||
header:
|
||||
type: object
|
||||
properties:
|
||||
properties:
|
||||
chain_id:
|
||||
type: string
|
||||
example: gaia-2
|
||||
height:
|
||||
height:
|
||||
type: number
|
||||
example: 1
|
||||
time:
|
||||
time:
|
||||
type: string
|
||||
example: '2017-12-30T05:53:09.287+01:00'
|
||||
num_txs:
|
||||
num_txs:
|
||||
type: number
|
||||
example: 0
|
||||
last_block_id:
|
||||
|
@ -753,17 +754,19 @@ definitions:
|
|||
type: array
|
||||
items:
|
||||
type: object
|
||||
Delegate:
|
||||
Validator:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
$ref: '#/definitions/ValidatorAddress'
|
||||
pub_key:
|
||||
$ref: "#/definitions/PubKey"
|
||||
$ref: "#/definitions/ValidatorPubKey"
|
||||
power:
|
||||
type: number
|
||||
example: 1000
|
||||
name:
|
||||
type: string
|
||||
example: "159.89.3.34"
|
||||
accum:
|
||||
type: number
|
||||
example: 1000
|
||||
# Added by API Auto Mocking Plugin
|
||||
host: virtserver.swaggerhub.com
|
||||
basePath: /faboweb1/Cosmos-LCD-2/1.0.0
|
||||
|
|
|
@ -203,7 +203,7 @@ where the ``--sequence`` flag is to be incremented for each transaction, the ``-
|
|||
|
||||
::
|
||||
|
||||
Please enter passphrase for alice:
|
||||
Please enter passphrase for alice:
|
||||
{
|
||||
"check_tx": {
|
||||
"gas": 30
|
||||
|
@ -250,7 +250,7 @@ First, we need the pub_key data:
|
|||
|
||||
::
|
||||
|
||||
cat $HOME/.gaia2/priv_validator.json
|
||||
cat $HOME/.gaia2/priv_validator.json
|
||||
|
||||
the first part will look like:
|
||||
|
||||
|
@ -260,17 +260,17 @@ the first part will look like:
|
|||
|
||||
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:
|
||||
|
||||
::
|
||||
|
||||
Please enter passphrase for bob:
|
||||
Please enter passphrase for bob:
|
||||
{
|
||||
"check_tx": {
|
||||
"gas": 30
|
||||
|
@ -285,7 +285,7 @@ We should see ``bob``'s account balance decrease by 10 mycoin:
|
|||
|
||||
::
|
||||
|
||||
gaiacli account 5D93A6059B6592833CBC8FA3DA90EE0382198985
|
||||
gaiacli account 5D93A6059B6592833CBC8FA3DA90EE0382198985
|
||||
|
||||
To confirm for certain the new validator is active, ask the tendermint node:
|
||||
|
||||
|
@ -306,19 +306,19 @@ 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``:
|
||||
|
||||
::
|
||||
|
||||
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:
|
||||
|
||||
::
|
||||
|
||||
Please enter passphrase for charlie:
|
||||
Please enter passphrase for charlie:
|
||||
{
|
||||
"check_tx": {
|
||||
"gas": 30
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -383,9 +383,9 @@ with an output similar to:
|
|||
"Shares": 20
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
See the bond decrease with ``gaiacli query delegator-bond`` like above.
|
||||
See the bond decrease with ``gaiacli stake delegation`` like above.
|
||||
|
|
|
@ -16,7 +16,7 @@ First, generate a couple of genesis transactions to be incorparated into the gen
|
|||
gaiacli keys list
|
||||
|
||||
**Note:** If you've already run these tests you may need to overwrite keys using the ``--OWK`` flag
|
||||
When you list the keys you should see two addresses, we'll need these later so take note.
|
||||
When you list the keys you should see two addresses, we'll need these later so take note.
|
||||
Now let's actually create the genesis files for both nodes:
|
||||
|
||||
::
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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!
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -14,6 +15,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
|
@ -29,10 +31,11 @@ type BasecoinApp struct {
|
|||
cdc *wire.Codec
|
||||
|
||||
// keys to access the substores
|
||||
keyMain *sdk.KVStoreKey
|
||||
keyAccount *sdk.KVStoreKey
|
||||
keyIBC *sdk.KVStoreKey
|
||||
keyStake *sdk.KVStoreKey
|
||||
keyMain *sdk.KVStoreKey
|
||||
keyAccount *sdk.KVStoreKey
|
||||
keyIBC *sdk.KVStoreKey
|
||||
keyStake *sdk.KVStoreKey
|
||||
keySlashing *sdk.KVStoreKey
|
||||
|
||||
// Manage getting and setting accounts
|
||||
accountMapper auth.AccountMapper
|
||||
|
@ -40,6 +43,7 @@ type BasecoinApp struct {
|
|||
coinKeeper bank.Keeper
|
||||
ibcMapper ibc.Mapper
|
||||
stakeKeeper stake.Keeper
|
||||
slashingKeeper slashing.Keeper
|
||||
}
|
||||
|
||||
func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||
|
@ -49,12 +53,13 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
|||
|
||||
// Create your application object.
|
||||
var app = &BasecoinApp{
|
||||
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
|
||||
cdc: cdc,
|
||||
keyMain: sdk.NewKVStoreKey("main"),
|
||||
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||
keyIBC: sdk.NewKVStoreKey("ibc"),
|
||||
keyStake: sdk.NewKVStoreKey("stake"),
|
||||
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
|
||||
cdc: cdc,
|
||||
keyMain: sdk.NewKVStoreKey("main"),
|
||||
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||
keyIBC: sdk.NewKVStoreKey("ibc"),
|
||||
keyStake: sdk.NewKVStoreKey("stake"),
|
||||
keySlashing: sdk.NewKVStoreKey("slashing"),
|
||||
}
|
||||
|
||||
// Define the accountMapper.
|
||||
|
@ -68,6 +73,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
|||
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
|
||||
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
|
||||
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace))
|
||||
|
||||
// register message routes
|
||||
app.Router().
|
||||
|
@ -78,8 +84,10 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
|||
|
||||
// Initialize BaseApp.
|
||||
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.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing)
|
||||
err := app.LoadLatestVersion(app.keyMain)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
|
@ -94,6 +102,7 @@ func MakeCodec() *wire.Codec {
|
|||
sdk.RegisterWire(cdc) // Register Msgs
|
||||
bank.RegisterWire(cdc)
|
||||
stake.RegisterWire(cdc)
|
||||
slashing.RegisterWire(cdc)
|
||||
ibc.RegisterWire(cdc)
|
||||
|
||||
// register custom AppAccount
|
||||
|
@ -102,6 +111,24 @@ func MakeCodec() *wire.Codec {
|
|||
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
|
||||
func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
stateJSON := req.AppStateBytes
|
||||
|
@ -121,11 +148,15 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
|
|||
}
|
||||
app.accountMapper.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
// load the initial stake information
|
||||
stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
|
||||
|
||||
return abci.ResponseInitChain{}
|
||||
}
|
||||
|
||||
// Custom logic for state export
|
||||
func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
||||
func (app *BasecoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||
ctx := app.NewContext(true, abci.Header{})
|
||||
|
||||
// iterate to get the accounts
|
||||
|
@ -143,5 +174,10 @@ func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
|
|||
genState := types.GenesisState{
|
||||
Accounts: accounts,
|
||||
}
|
||||
return wire.MarshalJSONIndent(app.cdc, genState)
|
||||
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
validators = stake.WriteValidators(ctx, app.stakeKeeper)
|
||||
return appState, validators, err
|
||||
}
|
||||
|
|
|
@ -11,9 +11,11 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/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/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
@ -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) {
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
||||
db := dbm.NewMemDB()
|
||||
|
@ -96,33 +122,11 @@ func newBasecoinApp() *BasecoinApp {
|
|||
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) {
|
||||
bapp := newBasecoinApp()
|
||||
require.Nil(t, setGenesis(bapp))
|
||||
|
||||
msgs := []struct {
|
||||
msg sdk.Msg
|
||||
|
@ -161,7 +165,7 @@ func TestSortGenesis(t *testing.T) {
|
|||
|
||||
// Initialize the chain
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, []byte(genState)})
|
||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: []byte(genState)})
|
||||
bapp.Commit()
|
||||
|
||||
// Unsorted coins means invalid
|
||||
|
@ -193,8 +197,8 @@ func TestGenesis(t *testing.T) {
|
|||
}
|
||||
acc := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
err = setGenesisAccounts(bapp, baseAcc)
|
||||
assert.Nil(t, err)
|
||||
err = setGenesis(bapp, baseAcc)
|
||||
require.Nil(t, err)
|
||||
|
||||
// A checkTx context
|
||||
ctx := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
|
@ -222,8 +226,9 @@ func TestMsgChangePubKey(t *testing.T) {
|
|||
}
|
||||
|
||||
// Construct genesis state
|
||||
err = setGenesisAccounts(bapp, baseAcc)
|
||||
assert.Nil(t, err)
|
||||
err = setGenesis(bapp, baseAcc)
|
||||
require.Nil(t, err)
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
|
@ -276,8 +281,9 @@ func TestMsgSendWithAccounts(t *testing.T) {
|
|||
}
|
||||
|
||||
// Construct genesis state
|
||||
err = setGenesisAccounts(bapp, baseAcc)
|
||||
assert.Nil(t, err)
|
||||
err = setGenesis(bapp, baseAcc)
|
||||
require.Nil(t, err)
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
|
@ -320,8 +326,9 @@ func TestMsgSendMultipleOut(t *testing.T) {
|
|||
Coins: genCoins,
|
||||
}
|
||||
|
||||
err = setGenesisAccounts(bapp, acc1, acc2)
|
||||
assert.Nil(t, err)
|
||||
// Construct genesis state
|
||||
err = setGenesis(bapp, acc1, acc2)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Simulate a Block
|
||||
SignCheckDeliver(t, bapp, sendMsg2, []int64{0}, true, priv1)
|
||||
|
@ -353,7 +360,7 @@ func TestSengMsgMultipleInOut(t *testing.T) {
|
|||
Coins: genCoins,
|
||||
}
|
||||
|
||||
err = setGenesisAccounts(bapp, acc1, acc2, acc4)
|
||||
err = setGenesis(bapp, acc1, acc2, acc4)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// CheckDeliver
|
||||
|
@ -377,7 +384,11 @@ func TestMsgSendDependent(t *testing.T) {
|
|||
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)
|
||||
|
||||
// CheckDeliver
|
||||
|
@ -416,7 +427,7 @@ func TestMsgQuiz(t *testing.T) {
|
|||
|
||||
// Initialize the chain (nil)
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
|
@ -438,8 +449,9 @@ func TestIBCMsgs(t *testing.T) {
|
|||
}
|
||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
||||
|
||||
err := setGenesisAccounts(bapp, baseAcc)
|
||||
err := setGenesis(bapp, baseAcc)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// A checkTx context (true)
|
||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||
|
|
|
@ -59,8 +59,8 @@ func main() {
|
|||
bankcmd.SendTxCmd(cdc),
|
||||
ibccmd.IBCTransferCmd(cdc),
|
||||
ibccmd.IBCRelayCmd(cdc),
|
||||
stakecmd.GetCmdDeclareCandidacy(cdc),
|
||||
stakecmd.GetCmdEditCandidacy(cdc),
|
||||
stakecmd.GetCmdCreateValidator(cdc),
|
||||
stakecmd.GetCmdEditValidator(cdc),
|
||||
stakecmd.GetCmdDelegate(cdc),
|
||||
stakecmd.GetCmdUnbond(cdc),
|
||||
)...)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -27,7 +28,7 @@ func main() {
|
|||
|
||||
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
|
||||
server.ConstructAppCreator(newApp, "basecoin"),
|
||||
server.ConstructAppExporter(exportAppState, "basecoin"))
|
||||
server.ConstructAppExporter(exportAppStateAndTMValidators, "basecoin"))
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
||||
|
@ -39,7 +40,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
|||
return app.NewBasecoinApp(logger, db)
|
||||
}
|
||||
|
||||
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
bapp := app.NewBasecoinApp(logger, db)
|
||||
return bapp.ExportAppStateJSON()
|
||||
return bapp.ExportAppStateAndValidators()
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
)
|
||||
|
||||
var _ auth.Account = (*AppAccount)(nil)
|
||||
|
@ -41,7 +42,8 @@ func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder {
|
|||
|
||||
// State to Unmarshal
|
||||
type GenesisState struct {
|
||||
Accounts []*GenesisAccount `json:"accounts"`
|
||||
Accounts []*GenesisAccount `json:"accounts"`
|
||||
StakeData stake.GenesisState `json:"stake"`
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -154,7 +155,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
|
|||
}
|
||||
|
||||
// Custom logic for state export
|
||||
func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
||||
func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||
ctx := app.NewContext(true, abci.Header{})
|
||||
|
||||
// iterate to get the accounts
|
||||
|
@ -174,5 +175,9 @@ func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
|
|||
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
|
||||
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
|
||||
}
|
||||
return wire.MarshalJSONIndent(app.cdc, genState)
|
||||
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return appState, validators, nil
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ func TestGenesis(t *testing.T) {
|
|||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context
|
||||
|
@ -184,7 +184,7 @@ func TestMsgSendWithAccounts(t *testing.T) {
|
|||
|
||||
// Initialize the chain
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
|
@ -262,7 +262,7 @@ func TestMsgMine(t *testing.T) {
|
|||
|
||||
// Initialize the chain (nil)
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
|
@ -309,7 +309,7 @@ func TestMsgQuiz(t *testing.T) {
|
|||
|
||||
// Initialize the chain (nil)
|
||||
vals := []abci.Validator{}
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
|
@ -356,7 +356,7 @@ func TestHandler(t *testing.T) {
|
|||
}
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
require.Nil(t, err)
|
||||
bapp.InitChain(abci.RequestInitChain{vals, stateBytes})
|
||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||
bapp.Commit()
|
||||
|
||||
// A checkTx context (true)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -46,9 +47,9 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
|||
return app.NewDemocoinApp(logger, db)
|
||||
}
|
||||
|
||||
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
dapp := app.NewDemocoinApp(logger, db)
|
||||
return dapp.ExportAppStateJSON()
|
||||
return dapp.ExportAppStateAndValidators()
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -63,7 +64,7 @@ func main() {
|
|||
|
||||
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
||||
server.ConstructAppCreator(newApp, "democoin"),
|
||||
server.ConstructAppExporter(exportAppState, "democoin"))
|
||||
server.ConstructAppExporter(exportAppStateAndTMValidators, "democoin"))
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.democoind")
|
||||
|
|
|
@ -2,6 +2,7 @@ package simplestake
|
|||
|
||||
import (
|
||||
abci "github.com/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/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{
|
||||
PubKey: msg.PubKey.Bytes(),
|
||||
PubKey: tmtypes.TM2PB.PubKey(msg.PubKey),
|
||||
Power: power,
|
||||
}
|
||||
|
||||
|
@ -44,7 +45,7 @@ func handleMsgUnbond(ctx sdk.Context, k Keeper, msg MsgUnbond) sdk.Result {
|
|||
}
|
||||
|
||||
valSet := abci.Validator{
|
||||
PubKey: pubKey.Bytes(),
|
||||
PubKey: tmtypes.TM2PB.PubKey(pubKey),
|
||||
Power: int64(0),
|
||||
}
|
||||
|
||||
|
|
|
@ -35,9 +35,9 @@ func TestKeeperGetSet(t *testing.T) {
|
|||
cdc := wire.NewCodec()
|
||||
auth.RegisterBaseAccount(cdc)
|
||||
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger())
|
||||
accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{})
|
||||
stakeKeeper := NewKeeper(capKey, bank.NewKeeper(accountMapper), DefaultCodespace)
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger())
|
||||
addr := sdk.Address([]byte("some-address"))
|
||||
|
||||
bi := stakeKeeper.getBondInfo(ctx, addr)
|
||||
|
|
|
@ -26,7 +26,7 @@ func NewMsgBond(addr sdk.Address, stake sdk.Coin, pubKey crypto.PubKey) MsgBond
|
|||
}
|
||||
|
||||
//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} }
|
||||
|
||||
// basic validation of the bond message
|
||||
|
@ -65,7 +65,7 @@ func NewMsgUnbond(addr sdk.Address) MsgUnbond {
|
|||
}
|
||||
|
||||
//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) ValidateBasic() sdk.Error { return nil }
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
@ -13,8 +14,8 @@ import (
|
|||
// and other flags (?) to start
|
||||
type AppCreator func(string, log.Logger) (abci.Application, error)
|
||||
|
||||
// AppExporter dumps all app state to JSON-serializable structure
|
||||
type AppExporter func(home string, log log.Logger) (json.RawMessage, error)
|
||||
// AppExporter dumps all app state to JSON-serializable structure and returns the current validator set
|
||||
type AppExporter func(home string, log log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error)
|
||||
|
||||
// ConstructAppCreator returns an application generation function
|
||||
func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator {
|
||||
|
@ -30,12 +31,12 @@ func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name s
|
|||
}
|
||||
|
||||
// ConstructAppExporter returns an application export function
|
||||
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, error), name string) AppExporter {
|
||||
return func(rootDir string, logger log.Logger) (json.RawMessage, error) {
|
||||
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error), name string) AppExporter {
|
||||
return func(rootDir string, logger log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
db, err := dbm.NewGoLevelDB(name, dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
return appFn(logger, db)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
|
|||
Short: "Export state to JSON",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
home := viper.GetString("home")
|
||||
appState, err := appExporter(home, ctx.Logger)
|
||||
appState, validators, err := appExporter(home, ctx.Logger)
|
||||
if err != nil {
|
||||
return errors.Errorf("Error exporting state: %v\n", err)
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
|
|||
return err
|
||||
}
|
||||
doc.AppStateJSON = appState
|
||||
doc.Validators = validators
|
||||
encoded, err := wire.MarshalJSONIndent(cdc, doc)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -37,7 +37,9 @@ func TestStartStandAlone(t *testing.T) {
|
|||
|
||||
app, err := mock.NewApp(home, logger)
|
||||
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")
|
||||
svr.SetLogger(logger.With("module", "abci-server"))
|
||||
svr.Start()
|
||||
|
@ -69,7 +71,9 @@ func TestStartWithTendermint(t *testing.T) {
|
|||
// set up app and start up
|
||||
viper.Set(flagWithTendermint, true)
|
||||
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
|
||||
|
||||
close(RunOrTimeout(startCmd, timeout, t))
|
||||
|
|
|
@ -16,14 +16,17 @@ import (
|
|||
|
||||
// Get a free address for a test tendermint server
|
||||
// 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")
|
||||
defer l.Close()
|
||||
require.Nil(t, err)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
port := l.Addr().(*net.TCPAddr).Port
|
||||
addr := fmt.Sprintf("tcp://0.0.0.0:%d", port)
|
||||
return addr
|
||||
portI := l.Addr().(*net.TCPAddr).Port
|
||||
port = fmt.Sprintf("%d", portI)
|
||||
addr = fmt.Sprintf("tcp://0.0.0.0:%s", port)
|
||||
return
|
||||
}
|
||||
|
||||
// setupViper creates a homedir to run inside,
|
||||
|
|
|
@ -53,11 +53,11 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
|
|||
fmt.Println(string(pubKeyJSONBytes))
|
||||
return nil
|
||||
}
|
||||
addr, err := sdk.Bech32CosmosifyValPub(valPubKey)
|
||||
pubkey, err := sdk.Bech32ifyValPub(valPubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(addr)
|
||||
fmt.Println(pubkey)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
|
@ -72,13 +73,24 @@ func AddCommands(
|
|||
|
||||
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(
|
||||
InitCmd(ctx, cdc, appInit),
|
||||
StartCmd(ctx, appCreator),
|
||||
UnsafeResetAllCmd(ctx),
|
||||
ShowNodeIDCmd(ctx),
|
||||
ShowValidatorCmd(ctx),
|
||||
client.LineBreak,
|
||||
tendermintCmd,
|
||||
ExportCmd(ctx, cdc, appExport),
|
||||
client.LineBreak,
|
||||
version.VersionCmd,
|
||||
)
|
||||
}
|
||||
|
|
104
tests/gobash.go
104
tests/gobash.go
|
@ -1,51 +1,91 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"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 := strings.Split(command, " ")
|
||||
// Split cmd to name and args.
|
||||
split := strings.Split(cmd, " ")
|
||||
require.True(t, len(split) > 0, "no command provided")
|
||||
|
||||
var cmd *exec.Cmd
|
||||
if len(split) == 1 {
|
||||
cmd = exec.Command(split[0])
|
||||
} else {
|
||||
cmd = exec.Command(split[0], split[1:]...)
|
||||
name, args := split[0], []string(nil)
|
||||
if len(split) > 1 {
|
||||
args = split[1:]
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Execute the command, return standard output and error, try a few times if requested
|
||||
func ExecuteT(t *testing.T, command string) (out string) {
|
||||
cmd := getCmd(t, command)
|
||||
bz, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
// Start process and wait.
|
||||
proc, err := StartProcess("", name, args, nil, nil)
|
||||
require.NoError(t, err)
|
||||
proc.Wait()
|
||||
|
||||
// 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))
|
||||
out = strings.Trim(string(bz), "\n") //trim any new lines
|
||||
time.Sleep(time.Second)
|
||||
if len(errbz) > 0 {
|
||||
t.Log("Stderr:", cmn.Red(string(errbz)))
|
||||
}
|
||||
|
||||
// Collect STDOUT output.
|
||||
out = strings.Trim(string(outbz), "\n") //trim any new lines
|
||||
return out
|
||||
}
|
||||
|
||||
// Asynchronously execute the command, return standard output and error
|
||||
func GoExecuteT(t *testing.T, command string) (cmd *exec.Cmd, pipeIn io.WriteCloser, pipeOut io.ReadCloser) {
|
||||
cmd = getCmd(t, command)
|
||||
pipeIn, err := cmd.StdinPipe()
|
||||
// Execute the command, launch goroutines to log stdout/err to t.
|
||||
// Caller should wait for .Wait() or .Stop() to terminate.
|
||||
func GoExecuteT(t *testing.T, cmd string) (proc *Process) {
|
||||
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)
|
||||
pipeOut, err = cmd.StdoutPipe()
|
||||
require.NoError(t, err)
|
||||
cmd.Start()
|
||||
time.Sleep(time.Second)
|
||||
return cmd, pipeIn, pipeOut
|
||||
|
||||
// Run goroutines to log stdout.
|
||||
go func() {
|
||||
buf := make([]byte, 10240) // TODO Document the effects.
|
||||
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/filepath"
|
||||
"strings"
|
||||
//"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -239,7 +238,9 @@ func StartNodeServerForTest(t *testing.T, home string) *exec.Cmd {
|
|||
// expects TestInitBaseCoin to have been run
|
||||
func StartLCDServerForTest(t *testing.T, home, chainID string) (cmd *exec.Cmd, port string) {
|
||||
cmdName := whereIsBasecli()
|
||||
port = strings.Split(server.FreeTCPAddr(t), ":")[2]
|
||||
var err error
|
||||
_, port, err = server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
cmdArgs := []string{
|
||||
"rest-server",
|
||||
"--home",
|
||||
|
@ -252,7 +253,7 @@ func StartLCDServerForTest(t *testing.T, home, chainID string) (cmd *exec.Cmd, p
|
|||
cmd = exec.Command(cmdName, cmdArgs...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Start()
|
||||
err = cmd.Start()
|
||||
require.Nil(t, err)
|
||||
time.Sleep(time.Second * 2) // TODO: LOL
|
||||
return cmd, port
|
||||
|
|
|
@ -11,16 +11,22 @@ import (
|
|||
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
||||
)
|
||||
|
||||
// TODO: these functions just print to Stdout.
|
||||
// consider using the logger.
|
||||
|
||||
// Uses localhost
|
||||
func WaitForHeight(height int64, port string) {
|
||||
for {
|
||||
var resultBlock ctypes.ResultBlock
|
||||
|
||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
||||
res, err := http.Get(url)
|
||||
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
|
||||
|
||||
// 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 {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -31,6 +37,7 @@ func WaitForHeight(height int64, port string) {
|
|||
}
|
||||
res.Body.Close()
|
||||
|
||||
var resultBlock ctypes.ResultBlock
|
||||
err = cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||
if err != nil {
|
||||
fmt.Println("RES", res)
|
||||
|
@ -45,45 +52,35 @@ func WaitForHeight(height int64, port string) {
|
|||
}
|
||||
}
|
||||
|
||||
// wait for 2 blocks.
|
||||
// uses localhost
|
||||
// wait for tendermint to start
|
||||
func WaitForStart(port string) {
|
||||
waitHeight := int64(2)
|
||||
for {
|
||||
var err error
|
||||
for i := 0; i < 5; i++ {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
|
||||
|
||||
// get url, try a few times
|
||||
var res *http.Response
|
||||
res, err = http.Get(url)
|
||||
if err == nil || res == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// waiting for server to start ...
|
||||
if res.StatusCode != http.StatusOK {
|
||||
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
|
||||
}
|
||||
}
|
||||
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
|
||||
func WaitForRPC(laddr string) {
|
||||
fmt.Println("LADDR", laddr)
|
||||
|
|
|
@ -5,8 +5,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
bech32cosmos "github.com/cosmos/bech32cosmos/go"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/tmlibs/bech32"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
|
@ -21,24 +21,24 @@ const (
|
|||
Bech32PrefixValPub = "cosmosvalpub"
|
||||
)
|
||||
|
||||
// Bech32CosmosifyAcc takes Address and returns the Bech32Cosmos encoded string
|
||||
func Bech32CosmosifyAcc(addr Address) (string, error) {
|
||||
return bech32cosmos.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes())
|
||||
// Bech32ifyAcc takes Address and returns the bech32 encoded string
|
||||
func Bech32ifyAcc(addr Address) (string, error) {
|
||||
return bech32.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes())
|
||||
}
|
||||
|
||||
// Bech32CosmosifyAccPub takes AccountPubKey and returns the Bech32Cosmos encoded string
|
||||
func Bech32CosmosifyAccPub(pub crypto.PubKey) (string, error) {
|
||||
return bech32cosmos.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
|
||||
// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string
|
||||
func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
|
||||
return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
|
||||
}
|
||||
|
||||
// Bech32CosmosifyVal returns the Bech32Cosmos encoded string for a validator address
|
||||
func Bech32CosmosifyVal(addr Address) (string, error) {
|
||||
return bech32cosmos.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes())
|
||||
// Bech32ifyVal returns the bech32 encoded string for a validator address
|
||||
func Bech32ifyVal(addr Address) (string, error) {
|
||||
return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes())
|
||||
}
|
||||
|
||||
// Bech32CosmosifyValPub returns the Bech32Cosmos encoded string for a validator pubkey
|
||||
func Bech32CosmosifyValPub(pub crypto.PubKey) (string, error) {
|
||||
return bech32cosmos.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
|
||||
// Bech32ifyValPub returns the bech32 encoded string for a validator pubkey
|
||||
func Bech32ifyValPub(pub crypto.PubKey) (string, error) {
|
||||
return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
|
||||
}
|
||||
|
||||
// create an Address from a string
|
||||
|
@ -54,14 +54,29 @@ func GetAccAddressHex(address string) (addr Address, err error) {
|
|||
}
|
||||
|
||||
// create an Address from a string
|
||||
func GetAccAddressBech32Cosmos(address string) (addr Address, err error) {
|
||||
bz, err := getFromBech32Cosmos(address, Bech32PrefixAccAddr)
|
||||
func GetAccAddressBech32(address string) (addr Address, err error) {
|
||||
bz, err := getFromBech32(address, Bech32PrefixAccAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Address(bz), nil
|
||||
}
|
||||
|
||||
// create a Pubkey from a string
|
||||
func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) {
|
||||
bz, err := getFromBech32(address, Bech32PrefixAccPub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk, err = crypto.PubKeyFromBytes(bz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// create an Address from a hex string
|
||||
func GetValAddressHex(address string) (addr Address, err error) {
|
||||
if len(address) == 0 {
|
||||
|
@ -74,9 +89,9 @@ func GetValAddressHex(address string) (addr Address, err error) {
|
|||
return Address(bz), nil
|
||||
}
|
||||
|
||||
// create an Address from a bech32cosmos string
|
||||
func GetValAddressBech32Cosmos(address string) (addr Address, err error) {
|
||||
bz, err := getFromBech32Cosmos(address, Bech32PrefixValAddr)
|
||||
// create an Address from a bech32 string
|
||||
func GetValAddressBech32(address string) (addr Address, err error) {
|
||||
bz, err := getFromBech32(address, Bech32PrefixValAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -84,8 +99,8 @@ func GetValAddressBech32Cosmos(address string) (addr Address, err error) {
|
|||
}
|
||||
|
||||
//Decode a validator publickey into a public key
|
||||
func GetValPubKeyBech32Cosmos(pubkey string) (pk crypto.PubKey, err error) {
|
||||
bz, err := getFromBech32Cosmos(pubkey, Bech32PrefixValPub)
|
||||
func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
|
||||
bz, err := getFromBech32(pubkey, Bech32PrefixValPub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -98,11 +113,11 @@ func GetValPubKeyBech32Cosmos(pubkey string) (pk crypto.PubKey, err error) {
|
|||
return pk, nil
|
||||
}
|
||||
|
||||
func getFromBech32Cosmos(bech32, prefix string) ([]byte, error) {
|
||||
if len(bech32) == 0 {
|
||||
func getFromBech32(bech32str, prefix string) ([]byte, error) {
|
||||
if len(bech32str) == 0 {
|
||||
return nil, errors.New("must provide non-empty string")
|
||||
}
|
||||
hrp, bz, err := bech32cosmos.DecodeAndConvert(bech32)
|
||||
hrp, bz, err := bech32.DecodeAndConvert(bech32str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ type Context struct {
|
|||
|
||||
// create a new context
|
||||
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byte, logger log.Logger) Context {
|
||||
|
||||
c := Context{
|
||||
Context: context.Background(),
|
||||
pst: newThePast(),
|
||||
|
@ -43,6 +44,7 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byt
|
|||
c = c.WithIsCheckTx(isCheckTx)
|
||||
c = c.WithTxBytes(txBytes)
|
||||
c = c.WithLogger(logger)
|
||||
c = c.WithSigningValidators(nil)
|
||||
c = c.WithGasMeter(NewInfiniteGasMeter())
|
||||
return c
|
||||
}
|
||||
|
@ -128,6 +130,7 @@ const (
|
|||
contextKeyIsCheckTx
|
||||
contextKeyTxBytes
|
||||
contextKeyLogger
|
||||
contextKeySigningValidators
|
||||
contextKeyGasMeter
|
||||
)
|
||||
|
||||
|
@ -157,6 +160,9 @@ func (c Context) TxBytes() []byte {
|
|||
func (c Context) Logger() 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 {
|
||||
return c.Value(contextKeyGasMeter).(GasMeter)
|
||||
}
|
||||
|
@ -182,6 +188,9 @@ func (c Context) WithTxBytes(txBytes []byte) Context {
|
|||
func (c Context) WithLogger(logger log.Logger) Context {
|
||||
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 {
|
||||
return c.withValue(contextKeyGasMeter, meter)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package types
|
|||
import (
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/go-crypto"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// status of a validator
|
||||
|
@ -31,6 +32,7 @@ func BondStatusToString(b BondStatus) string {
|
|||
|
||||
// validator for a delegated proof of stake system
|
||||
type Validator interface {
|
||||
GetMoniker() string // moniker of the validator
|
||||
GetStatus() BondStatus // status of the validator
|
||||
GetOwner() Address // owner address to receive/return validators coins
|
||||
GetPubKey() crypto.PubKey // validation pubkey
|
||||
|
@ -41,7 +43,7 @@ type Validator interface {
|
|||
// validator which fulfills abci validator interface for use in Tendermint
|
||||
func ABCIValidator(v Validator) abci.Validator {
|
||||
return abci.Validator{
|
||||
PubKey: v.GetPubKey().Bytes(),
|
||||
PubKey: tmtypes.TM2PB.PubKey(v.GetPubKey()),
|
||||
Power: v.GetPower().Evaluate(),
|
||||
}
|
||||
}
|
||||
|
@ -56,8 +58,11 @@ type ValidatorSet interface {
|
|||
IterateValidatorsBonded(Context,
|
||||
func(index int64, validator Validator) (stop bool))
|
||||
|
||||
Validator(Context, Address) Validator // get a particular validator by owner address
|
||||
TotalPower(Context) Rat // total power of the validator set
|
||||
Validator(Context, Address) Validator // get a particular validator by owner address
|
||||
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...)
|
||||
}
|
||||
|
||||
// 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
|
||||
func NewTags(tags ...interface{}) 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)
|
||||
|
||||
//__________________________________________________________
|
||||
|
|
|
@ -40,7 +40,7 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode
|
|||
// find the key to look up the account
|
||||
addr := args[0]
|
||||
|
||||
key, err := sdk.GetAccAddressBech32Cosmos(addr)
|
||||
key, err := sdk.GetAccAddressBech32(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"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 {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
addr := vars["address"]
|
||||
bech32addr := vars["address"]
|
||||
|
||||
bz, err := hex.DecodeString(addr)
|
||||
addr, err := sdk.GetAccAddressBech32(bech32addr)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
key := sdk.Address(bz)
|
||||
|
||||
res, err := ctx.Query(key, storeName)
|
||||
res, err := ctx.Query(addr, storeName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error())))
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
@ -30,7 +28,7 @@ func (msg MsgChangeKey) ValidateBasic() sdk.Error {
|
|||
|
||||
// Implements Msg.
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
@ -70,7 +68,7 @@ func (fee StdFee) Bytes() []byte {
|
|||
if len(fee.Amount) == 0 {
|
||||
fee.Amount = sdk.Coins{}
|
||||
}
|
||||
bz, err := json.Marshal(fee) // TODO
|
||||
bz, err := msgCdc.MarshalJSON(fee) // TODO
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -95,7 +93,7 @@ type StdSignDoc struct {
|
|||
// StdSignBytes returns the bytes to sign for a transaction.
|
||||
// TODO: change the API to just take a chainID and StdTx ?
|
||||
func StdSignBytes(chainID string, sequences []int64, fee StdFee, msg sdk.Msg) []byte {
|
||||
bz, err := json.Marshal(StdSignDoc{
|
||||
bz, err := msgCdc.MarshalJSON(StdSignDoc{
|
||||
ChainID: chainID,
|
||||
Sequences: sequences,
|
||||
FeeBytes: fee.Bytes(),
|
||||
|
|
|
@ -10,3 +10,10 @@ func RegisterWire(cdc *wire.Codec) {
|
|||
cdc.RegisterConcrete(&BaseAccount{}, "auth/Account", 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)
|
||||
|
||||
to, err := sdk.GetAccAddressBech32Cosmos(toStr)
|
||||
to, err := sdk.GetAccAddressBech32(toStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"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/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/client"
|
||||
)
|
||||
|
||||
|
@ -29,12 +30,25 @@ type sendBody struct {
|
|||
Sequence int64 `json:"sequence"`
|
||||
}
|
||||
|
||||
var msgCdc = wire.NewCodec()
|
||||
|
||||
func init() {
|
||||
bank.RegisterWire(msgCdc)
|
||||
}
|
||||
|
||||
// SendRequestHandlerFn - http request handler to send coins to a address
|
||||
func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// collect data
|
||||
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
|
||||
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()))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &m)
|
||||
err = msgCdc.UnmarshalJSON(body, &m)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
@ -57,7 +71,7 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont
|
|||
return
|
||||
}
|
||||
|
||||
to, err := sdk.GetAccAddressHex(address)
|
||||
to, err := sdk.GetAccAddressHex(address.String())
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package bank
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
|
@ -55,7 +53,7 @@ func (msg MsgSend) ValidateBasic() sdk.Error {
|
|||
|
||||
// Implements Msg.
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -104,7 +102,7 @@ func (msg MsgIssue) ValidateBasic() sdk.Error {
|
|||
|
||||
// Implements Msg.
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -186,8 +186,14 @@ func TestMsgSendGetSignBytes(t *testing.T) {
|
|||
Outputs: []Output{NewOutput(addr2, coins)},
|
||||
}
|
||||
res := msg.GetSignBytes()
|
||||
|
||||
unmarshaledMsg := &MsgSend{}
|
||||
msgCdc.UnmarshalJSON(res, unmarshaledMsg)
|
||||
assert.Equal(t, &msg, unmarshaledMsg)
|
||||
|
||||
// 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) {
|
||||
|
@ -255,8 +261,14 @@ func TestMsgIssueGetSignBytes(t *testing.T) {
|
|||
Outputs: []Output{NewOutput(addr, coins)},
|
||||
}
|
||||
res := msg.GetSignBytes()
|
||||
|
||||
unmarshaledMsg := &MsgIssue{}
|
||||
msgCdc.UnmarshalJSON(res, unmarshaledMsg)
|
||||
assert.Equal(t, &msg, unmarshaledMsg)
|
||||
|
||||
// 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) {
|
||||
|
|
|
@ -9,3 +9,9 @@ func RegisterWire(cdc *wire.Codec) {
|
|||
cdc.RegisterConcrete(MsgSend{}, "cosmos-sdk/Send", 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
|
||||
vars := mux.Vars(r)
|
||||
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
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
|
@ -58,7 +65,7 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
|
|||
return
|
||||
}
|
||||
|
||||
bz, err := hex.DecodeString(address)
|
||||
bz, err := hex.DecodeString(address.String())
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
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),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
addr, err := sdk.GetAccAddressBech32Cosmos(args[0])
|
||||
addr, err := sdk.GetAccAddressBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -72,25 +72,25 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
// parse out the candidates
|
||||
var candidates []stake.Validator
|
||||
// parse out the validators
|
||||
var validators []stake.Validator
|
||||
for _, KV := range resKVs {
|
||||
var validator stake.Validator
|
||||
cdc.MustUnmarshalBinary(KV.Value, &validator)
|
||||
candidates = append(candidates, validator)
|
||||
validators = append(validators, validator)
|
||||
}
|
||||
|
||||
switch viper.Get(cli.OutputFlag) {
|
||||
case "text":
|
||||
for _, candidate := range candidates {
|
||||
resp, err := candidate.HumanReadableString()
|
||||
for _, validator := range validators {
|
||||
resp, err := validator.HumanReadableString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(resp)
|
||||
}
|
||||
case "json":
|
||||
output, err := wire.MarshalJSONIndent(cdc, candidates)
|
||||
output, err := wire.MarshalJSONIndent(cdc, validators)
|
||||
if err != nil {
|
||||
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",
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
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 {
|
||||
cmd := &cobra.Command{
|
||||
Use: "delegations [delegator-addr]",
|
||||
|
@ -165,7 +165,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(args[0])
|
||||
delegatorAddr, err := sdk.GetAccAddressBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
// parse out the candidates
|
||||
// parse out the validators
|
||||
var delegations []stake.Delegation
|
||||
for _, KV := range resKVs {
|
||||
var delegation stake.Delegation
|
||||
|
|
|
@ -13,8 +13,8 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
)
|
||||
|
||||
// create declare candidacy command
|
||||
func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
||||
// create create validator command
|
||||
func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "create-validator",
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator))
|
||||
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
|||
if len(pkStr) == 0 {
|
||||
return fmt.Errorf("must use --pubkey flag")
|
||||
}
|
||||
pk, err := sdk.GetValPubKeyBech32Cosmos(pkStr)
|
||||
pk, err := sdk.GetValPubKeyBech32(pkStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
|||
Website: viper.GetString(FlagWebsite),
|
||||
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
|
||||
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, msg, cdc)
|
||||
|
@ -67,14 +67,14 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
// create edit candidacy command
|
||||
func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command {
|
||||
// create edit validator command
|
||||
func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "edit-validator",
|
||||
Short: "edit and existing validator account",
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command {
|
|||
Website: viper.GetString(FlagWebsite),
|
||||
Details: viper.GetString(FlagDetails),
|
||||
}
|
||||
msg := stake.NewMsgEditCandidacy(validatorAddr, description)
|
||||
msg := stake.NewMsgEditValidator(validatorAddr, description)
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
|
@ -104,7 +104,7 @@ func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
// create edit candidacy command
|
||||
// create edit validator command
|
||||
func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "delegate",
|
||||
|
@ -115,8 +115,8 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressDelegator))
|
||||
validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator))
|
||||
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
||||
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
// create edit candidacy command
|
||||
// create edit validator command
|
||||
func GetCmdUnbond(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "unbond",
|
||||
|
@ -163,8 +163,8 @@ func GetCmdUnbond(cdc *wire.Codec) *cobra.Command {
|
|||
}
|
||||
}
|
||||
|
||||
delegatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressDelegator))
|
||||
validatorAddr, err := sdk.GetAccAddressBech32Cosmos(viper.GetString(FlagAddressValidator))
|
||||
delegatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
||||
validatorAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressValidator))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -14,34 +12,39 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
)
|
||||
|
||||
// RegisterRoutes - Central function to define routes that get registered by the main application
|
||||
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
|
||||
r.HandleFunc("/stake/{delegator}/bonding_status/{validator}", BondingStatusHandlerFn("stake", cdc, kb, ctx)).Methods("GET")
|
||||
func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
|
||||
r.HandleFunc(
|
||||
"/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
|
||||
func BondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
|
||||
// http request handler to query delegator bonding status
|
||||
func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// read parameters
|
||||
vars := mux.Vars(r)
|
||||
delegator := vars["delegator"]
|
||||
validator := vars["validator"]
|
||||
bech32delegator := vars["delegator"]
|
||||
bech32validator := vars["validator"]
|
||||
|
||||
bz, err := hex.DecodeString(delegator)
|
||||
delegatorAddr, err := sdk.GetAccAddressBech32(bech32delegator)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
delegatorAddr := sdk.Address(bz)
|
||||
|
||||
bz, err = hex.DecodeString(validator)
|
||||
validatorAddr, err := sdk.GetValAddressBech32(bech32validator)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
validatorAddr := sdk.Address(bz)
|
||||
|
||||
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
|
||||
|
||||
|
@ -76,3 +79,103 @@ func BondingStatusHandlerFn(storeName string, cdc *wire.Codec, kb keys.Keybase,
|
|||
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
|
||||
func (b Delegation) HumanReadableString() (string, error) {
|
||||
bechAcc, err := sdk.Bech32CosmosifyAcc(b.DelegatorAddr)
|
||||
bechAcc, err := sdk.Bech32ifyAcc(b.DelegatorAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bechVal, err := sdk.Bech32CosmosifyAcc(b.ValidatorAddr)
|
||||
bechVal, err := sdk.Bech32ifyAcc(b.ValidatorAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ const (
|
|||
CodeInvalidValidator CodeType = 201
|
||||
CodeInvalidBond CodeType = 202
|
||||
CodeInvalidInput CodeType = 203
|
||||
CodeValidatorJailed CodeType = 204
|
||||
CodeUnauthorized CodeType = sdk.CodeUnauthorized
|
||||
CodeInternal CodeType = sdk.CodeInternal
|
||||
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")
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
return newError(codespace, CodeInvalidValidator, "Missing signature")
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
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
|
||||
type GenesisState struct {
|
||||
|
@ -22,21 +26,32 @@ func NewGenesisState(pool Pool, params Params, validators []Validator, bonds []D
|
|||
// get raw genesis raw message for testing
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return GenesisState{
|
||||
Pool: initialPool(),
|
||||
Params: defaultParams(),
|
||||
Pool: InitialPool(),
|
||||
Params: DefaultParams(),
|
||||
}
|
||||
}
|
||||
|
||||
// InitGenesis - store genesis parameters
|
||||
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
k.setPool(ctx, data.Pool)
|
||||
k.setNewParams(ctx, data.Params)
|
||||
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 {
|
||||
k.setDelegation(ctx, bond)
|
||||
}
|
||||
k.updateBondedValidatorsFull(ctx, store)
|
||||
}
|
||||
|
||||
// WriteGenesis - output genesis parameters
|
||||
|
@ -52,3 +67,16 @@ func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState {
|
|||
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 {
|
||||
// NOTE msg already has validate basic run
|
||||
switch msg := msg.(type) {
|
||||
case MsgDeclareCandidacy:
|
||||
return handleMsgDeclareCandidacy(ctx, msg, k)
|
||||
case MsgEditCandidacy:
|
||||
return handleMsgEditCandidacy(ctx, msg, k)
|
||||
case MsgCreateValidator:
|
||||
return handleMsgCreateValidator(ctx, msg, k)
|
||||
case MsgEditValidator:
|
||||
return handleMsgEditValidator(ctx, msg, k)
|
||||
case MsgDelegate:
|
||||
return handleMsgDelegate(ctx, msg, k)
|
||||
case MsgUnbond:
|
||||
|
@ -25,13 +25,27 @@ func NewHandler(k Keeper) sdk.Handler {
|
|||
}
|
||||
}
|
||||
|
||||
// NewEndBlocker generates sdk.EndBlocker
|
||||
// Performs tick functionality
|
||||
func NewEndBlocker(k Keeper) sdk.EndBlocker {
|
||||
return func(ctx sdk.Context, req abci.RequestEndBlock) (res abci.ResponseEndBlock) {
|
||||
res.ValidatorUpdates = k.Tick(ctx)
|
||||
return
|
||||
// Called every block, process inflation, update validator set
|
||||
func EndBlocker(ctx sdk.Context, k Keeper) (ValidatorUpdates []abci.Validator) {
|
||||
pool := k.GetPool(ctx)
|
||||
|
||||
// Process Validator Provisions
|
||||
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,
|
||||
// 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
|
||||
_, 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)
|
||||
k.setValidator(ctx, validator)
|
||||
k.setValidatorByPubKeyIndex(ctx, validator)
|
||||
tags := sdk.NewTags(
|
||||
"action", []byte("declareCandidacy"),
|
||||
"action", []byte("createValidator"),
|
||||
"validator", msg.ValidatorAddr.Bytes(),
|
||||
"moniker", []byte(msg.Description.Moniker),
|
||||
"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, found := k.GetValidator(ctx, msg.ValidatorAddr)
|
||||
|
@ -94,7 +109,7 @@ func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk
|
|||
|
||||
k.updateValidator(ctx, validator)
|
||||
tags := sdk.NewTags(
|
||||
"action", []byte("editCandidacy"),
|
||||
"action", []byte("editValidator"),
|
||||
"validator", msg.ValidatorAddr.Bytes(),
|
||||
"moniker", []byte(msg.Description.Moniker),
|
||||
"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)
|
||||
|
||||
// remove the bond
|
||||
revokeCandidacy := false
|
||||
revokeValidator := false
|
||||
if bond.Shares.IsZero() {
|
||||
|
||||
// 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) &&
|
||||
validator.Revoked == false {
|
||||
revokeCandidacy = true
|
||||
revokeValidator = true
|
||||
}
|
||||
|
||||
k.removeDelegation(ctx, bond)
|
||||
|
@ -232,7 +247,7 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result {
|
|||
|
||||
/////////////////////////////////////
|
||||
// revoke validator if necessary
|
||||
if revokeCandidacy {
|
||||
if revokeValidator {
|
||||
validator.Revoked = true
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ import (
|
|||
|
||||
//______________________________________________________________________
|
||||
|
||||
func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) MsgDeclareCandidacy {
|
||||
return MsgDeclareCandidacy{
|
||||
func newTestMsgCreateValidator(address sdk.Address, pubKey crypto.PubKey, amt int64) MsgCreateValidator {
|
||||
return MsgCreateValidator{
|
||||
Description: Description{},
|
||||
ValidatorAddr: address,
|
||||
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)
|
||||
|
||||
validatorAddr := addrs[0]
|
||||
pk := pks[0]
|
||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pk, 10)
|
||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pk, 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
assert.True(t, got.IsOK(), "%v", got)
|
||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
|
@ -51,8 +51,8 @@ func TestDuplicatesMsgDeclareCandidacy(t *testing.T) {
|
|||
assert.Equal(t, Description{}, validator.Description)
|
||||
|
||||
// one validator cannot bond twice
|
||||
msgDeclareCandidacy.PubKey = pks[1]
|
||||
got = handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
||||
msgCreateValidator.PubKey = pks[1]
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
assert.False(t, got.IsOK(), "%v", got)
|
||||
}
|
||||
|
||||
|
@ -64,10 +64,10 @@ func TestIncrementsMsgDelegate(t *testing.T) {
|
|||
bondAmount := int64(10)
|
||||
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
||||
|
||||
// first declare candidacy
|
||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], bondAmount)
|
||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
||||
assert.True(t, got.IsOK(), "expected declare candidacy msg to be ok, got %v", got)
|
||||
// first create validator
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], bondAmount)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
assert.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got)
|
||||
|
||||
validator, found := keeper.GetValidator(ctx, validatorAddr)
|
||||
require.True(t, found)
|
||||
|
@ -134,12 +134,12 @@ func TestIncrementsMsgUnbond(t *testing.T) {
|
|||
ctx, accMapper, keeper := createTestInput(t, false, initBond)
|
||||
params := keeper.GetParams(ctx)
|
||||
|
||||
// declare candidacy, delegate
|
||||
// create validator, delegate
|
||||
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
||||
|
||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], initBond)
|
||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
||||
assert.True(t, got.IsOK(), "expected declare-candidacy to be ok, got %v", got)
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], initBond)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
assert.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
|
||||
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, initBond)
|
||||
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)
|
||||
}
|
||||
|
||||
func TestMultipleMsgDeclareCandidacy(t *testing.T) {
|
||||
func TestMultipleMsgCreateValidator(t *testing.T) {
|
||||
initBond := int64(1000)
|
||||
ctx, accMapper, keeper := createTestInput(t, false, initBond)
|
||||
params := keeper.GetParams(ctx)
|
||||
|
@ -224,8 +224,8 @@ func TestMultipleMsgDeclareCandidacy(t *testing.T) {
|
|||
|
||||
// bond them all
|
||||
for i, validatorAddr := range validatorAddrs {
|
||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[i], 10)
|
||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[i], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
|
||||
|
||||
//Check that the account is bonded
|
||||
|
@ -266,8 +266,8 @@ func TestMultipleMsgDelegate(t *testing.T) {
|
|||
validatorAddr, delegatorAddrs := addrs[0], addrs[1:]
|
||||
|
||||
//first make a validator
|
||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], 10)
|
||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
|
||||
|
||||
// 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)
|
||||
validatorAddr, delegatorAddr := addrs[0], addrs[1]
|
||||
|
||||
// create the validator
|
||||
msgDeclareCandidacy := newTestMsgDeclareCandidacy(validatorAddr, pks[0], 10)
|
||||
got := handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgDeclareCandidacy")
|
||||
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], 10)
|
||||
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
|
||||
|
||||
// bond a delegator
|
||||
msgDelegate := newTestMsgDelegate(delegatorAddr, validatorAddr, 10)
|
||||
|
@ -311,7 +311,7 @@ func TestVoidCandidacy(t *testing.T) {
|
|||
// unbond the validators bond portion
|
||||
msgUnbondValidator := NewMsgUnbond(validatorAddr, validatorAddr, "10")
|
||||
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)
|
||||
require.True(t, found)
|
||||
require.True(t, validator.Revoked)
|
||||
|
@ -323,9 +323,9 @@ func TestVoidCandidacy(t *testing.T) {
|
|||
// test that the delegator can still withdraw their bonds
|
||||
msgUnbondDelegator := NewMsgUnbond(delegatorAddr, validatorAddr, "10")
|
||||
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
|
||||
got = handleMsgDeclareCandidacy(ctx, msgDeclareCandidacy, keeper)
|
||||
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
|
||||
assert.True(t, got.IsOK(), "expected ok, got %v", got)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package stake
|
|||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -12,30 +11,6 @@ const (
|
|||
|
||||
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
|
||||
func (k Keeper) processProvisions(ctx sdk.Context) Pool {
|
||||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
func (k Keeper) getValidator(store sdk.KVStore, addr sdk.Address) (validator Validator, found bool) {
|
||||
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
|
||||
func (k Keeper) setValidator(ctx sdk.Context, validator Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
// set main store
|
||||
bz := k.cdc.MustMarshalBinary(validator)
|
||||
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
|
||||
func (k Keeper) getAllValidators(ctx sdk.Context) (validators Validators) {
|
||||
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)
|
||||
|
||||
if validator.Revoked && oldValidator.Status() == sdk.Bonded {
|
||||
validator, pool = validator.UpdateStatus(pool, sdk.Unbonded)
|
||||
k.setPool(ctx, pool)
|
||||
validator = k.unbondValidator(ctx, store, validator)
|
||||
|
||||
// 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
|
||||
|
@ -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
|
||||
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)
|
||||
|
||||
// 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
|
||||
store.Delete(GetValidatorsBondedKey(validator.PubKey))
|
||||
return validator
|
||||
}
|
||||
|
||||
// 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)
|
||||
pool := k.getPool(store)
|
||||
store.Delete(GetValidatorKey(address))
|
||||
store.Delete(GetValidatorByPubKeyIndexKey(validator.PubKey))
|
||||
store.Delete(GetValidatorsByPowerKey(validator, pool))
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (k Keeper) setPool(ctx sdk.Context, p Pool) {
|
||||
func (k Keeper) setPool(ctx sdk.Context, pool Pool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinary(p)
|
||||
b := k.cdc.MustMarshalBinary(pool)
|
||||
store.Set(PoolKey, b)
|
||||
}
|
||||
|
||||
|
@ -656,6 +685,13 @@ func (k Keeper) setCliffValidator(ctx sdk.Context, validator Validator, pool Poo
|
|||
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
|
||||
|
@ -749,3 +785,46 @@ func (k Keeper) IterateDelegators(ctx sdk.Context, delAddr sdk.Address, fn func(
|
|||
}
|
||||
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
|
||||
}
|
||||
|
|
|
@ -13,16 +13,17 @@ import (
|
|||
//nolint
|
||||
var (
|
||||
// Keys for store prefixes
|
||||
ParamKey = []byte{0x00} // key for parameters relating to staking
|
||||
PoolKey = []byte{0x01} // key for the staking pools
|
||||
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
|
||||
ValidatorsBondedKey = []byte{0x03} // prefix for each key to bonded/actively validating validators
|
||||
ValidatorsByPowerKey = []byte{0x04} // prefix for each key to a validator sorted by power
|
||||
ValidatorCliffKey = []byte{0x05} // key for block-local tx index
|
||||
ValidatorPowerCliffKey = []byte{0x06} // key for block-local tx index
|
||||
TendermintUpdatesKey = []byte{0x07} // prefix for each key to a validator which is being updated
|
||||
DelegationKey = []byte{0x08} // prefix for each key to a delegator's bond
|
||||
IntraTxCounterKey = []byte{0x09} // key for block-local tx index
|
||||
ParamKey = []byte{0x00} // key for parameters relating to staking
|
||||
PoolKey = []byte{0x01} // key for the staking pools
|
||||
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
|
||||
ValidatorsByPubKeyIndexKey = []byte{0x03} // prefix for each key to a validator by pubkey
|
||||
ValidatorsBondedKey = []byte{0x04} // prefix for each key to bonded/actively validating validators
|
||||
ValidatorsByPowerKey = []byte{0x05} // prefix for each key to a validator sorted by power
|
||||
ValidatorCliffKey = []byte{0x06} // key for block-local tx index
|
||||
ValidatorPowerCliffKey = []byte{0x07} // key for block-local tx index
|
||||
TendermintUpdatesKey = []byte{0x08} // prefix for each key to a validator which is being updated
|
||||
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
|
||||
|
@ -32,6 +33,11 @@ func GetValidatorKey(ownerAddr sdk.Address) []byte {
|
|||
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
|
||||
func GetValidatorsBondedKey(pk crypto.PubKey) []byte {
|
||||
addr := pk.Address()
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -463,8 +464,8 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) {
|
|||
|
||||
updates = keeper.getTendermintUpdates(ctx)
|
||||
require.Equal(t, 2, len(updates))
|
||||
assert.Equal(t, validators[0].PubKey.Bytes(), updates[0].PubKey)
|
||||
assert.Equal(t, validators[1].PubKey.Bytes(), updates[1].PubKey)
|
||||
assert.Equal(t, tmtypes.TM2PB.PubKey(validators[0].PubKey), updates[0].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[1].Power)
|
||||
}
|
||||
|
@ -586,7 +587,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) {
|
|||
|
||||
func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) {
|
||||
ctx, _, keeper := createTestInput(t, false, 0)
|
||||
params := defaultParams()
|
||||
params := DefaultParams()
|
||||
params.MaxValidators = 2
|
||||
keeper.setParams(ctx, params)
|
||||
|
||||
|
@ -721,7 +722,7 @@ func TestBond(t *testing.T) {
|
|||
|
||||
func TestParams(t *testing.T) {
|
||||
ctx, _, keeper := createTestInput(t, false, 0)
|
||||
expParams := defaultParams()
|
||||
expParams := DefaultParams()
|
||||
|
||||
//check that the empty keeper loads the default
|
||||
resParams := keeper.GetParams(ctx)
|
||||
|
@ -736,7 +737,7 @@ func TestParams(t *testing.T) {
|
|||
|
||||
func TestPool(t *testing.T) {
|
||||
ctx, _, keeper := createTestInput(t, false, 0)
|
||||
expPool := initialPool()
|
||||
expPool := InitialPool()
|
||||
|
||||
//check that the empty keeper loads the default
|
||||
resPool := keeper.GetPool(ctx)
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package stake
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
|
@ -18,27 +15,21 @@ const MsgType = "stake"
|
|||
const StakingToken = "steak"
|
||||
|
||||
//Verify interface at compile time
|
||||
var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelegate{}, &MsgUnbond{}
|
||||
|
||||
var msgCdc = wire.NewCodec()
|
||||
|
||||
func init() {
|
||||
wire.RegisterCrypto(msgCdc)
|
||||
}
|
||||
var _, _, _, _ sdk.Msg = &MsgCreateValidator{}, &MsgEditValidator{}, &MsgDelegate{}, &MsgUnbond{}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgDeclareCandidacy - struct for unbonding transactions
|
||||
type MsgDeclareCandidacy struct {
|
||||
// MsgCreateValidator - struct for unbonding transactions
|
||||
type MsgCreateValidator struct {
|
||||
Description
|
||||
ValidatorAddr sdk.Address `json:"address"`
|
||||
PubKey crypto.PubKey `json:"pubkey"`
|
||||
Bond sdk.Coin `json:"bond"`
|
||||
}
|
||||
|
||||
func NewMsgDeclareCandidacy(validatorAddr sdk.Address, pubkey crypto.PubKey,
|
||||
bond sdk.Coin, description Description) MsgDeclareCandidacy {
|
||||
return MsgDeclareCandidacy{
|
||||
func NewMsgCreateValidator(validatorAddr sdk.Address, pubkey crypto.PubKey,
|
||||
bond sdk.Coin, description Description) MsgCreateValidator {
|
||||
return MsgCreateValidator{
|
||||
Description: description,
|
||||
ValidatorAddr: validatorAddr,
|
||||
PubKey: pubkey,
|
||||
|
@ -47,18 +38,18 @@ func NewMsgDeclareCandidacy(validatorAddr sdk.Address, pubkey crypto.PubKey,
|
|||
}
|
||||
|
||||
//nolint
|
||||
func (msg MsgDeclareCandidacy) Type() string { return MsgType } //TODO update "stake/declarecandidacy"
|
||||
func (msg MsgDeclareCandidacy) GetSigners() []sdk.Address {
|
||||
func (msg MsgCreateValidator) Type() string { return MsgType }
|
||||
func (msg MsgCreateValidator) GetSigners() []sdk.Address {
|
||||
return []sdk.Address{msg.ValidatorAddr}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgDeclareCandidacy) GetSignBytes() []byte {
|
||||
func (msg MsgCreateValidator) GetSignBytes() []byte {
|
||||
return msgCdc.MustMarshalBinary(msg)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error {
|
||||
func (msg MsgCreateValidator) ValidateBasic() sdk.Error {
|
||||
if msg.ValidatorAddr == nil {
|
||||
return ErrValidatorEmpty(DefaultCodespace)
|
||||
}
|
||||
|
@ -77,28 +68,28 @@ func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error {
|
|||
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgEditCandidacy - struct for editing a validator
|
||||
type MsgEditCandidacy struct {
|
||||
// MsgEditValidator - struct for editing a validator
|
||||
type MsgEditValidator struct {
|
||||
Description
|
||||
ValidatorAddr sdk.Address `json:"address"`
|
||||
}
|
||||
|
||||
func NewMsgEditCandidacy(validatorAddr sdk.Address, description Description) MsgEditCandidacy {
|
||||
return MsgEditCandidacy{
|
||||
func NewMsgEditValidator(validatorAddr sdk.Address, description Description) MsgEditValidator {
|
||||
return MsgEditValidator{
|
||||
Description: description,
|
||||
ValidatorAddr: validatorAddr,
|
||||
}
|
||||
}
|
||||
|
||||
//nolint
|
||||
func (msg MsgEditCandidacy) Type() string { return MsgType } //TODO update "stake/msgeditcandidacy"
|
||||
func (msg MsgEditCandidacy) GetSigners() []sdk.Address {
|
||||
func (msg MsgEditValidator) Type() string { return MsgType }
|
||||
func (msg MsgEditValidator) GetSigners() []sdk.Address {
|
||||
return []sdk.Address{msg.ValidatorAddr}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgEditCandidacy) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
func (msg MsgEditValidator) GetSignBytes() []byte {
|
||||
b, err := msgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -106,7 +97,7 @@ func (msg MsgEditCandidacy) GetSignBytes() []byte {
|
|||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgEditCandidacy) ValidateBasic() sdk.Error {
|
||||
func (msg MsgEditValidator) ValidateBasic() sdk.Error {
|
||||
if msg.ValidatorAddr == nil {
|
||||
return ErrValidatorEmpty(DefaultCodespace)
|
||||
}
|
||||
|
@ -121,8 +112,8 @@ func (msg MsgEditCandidacy) ValidateBasic() sdk.Error {
|
|||
|
||||
// MsgDelegate - struct for bonding transactions
|
||||
type MsgDelegate struct {
|
||||
DelegatorAddr sdk.Address `json:"address"`
|
||||
ValidatorAddr sdk.Address `json:"address"`
|
||||
DelegatorAddr sdk.Address `json:"delegator_addr"`
|
||||
ValidatorAddr sdk.Address `json:"validator_addr"`
|
||||
Bond sdk.Coin `json:"bond"`
|
||||
}
|
||||
|
||||
|
@ -135,14 +126,14 @@ func NewMsgDelegate(delegatorAddr, validatorAddr sdk.Address, bond sdk.Coin) Msg
|
|||
}
|
||||
|
||||
//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 {
|
||||
return []sdk.Address{msg.DelegatorAddr}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgDelegate) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
b, err := msgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -170,8 +161,8 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error {
|
|||
|
||||
// MsgUnbond - struct for unbonding transactions
|
||||
type MsgUnbond struct {
|
||||
DelegatorAddr sdk.Address `json:"address"`
|
||||
ValidatorAddr sdk.Address `json:"address"`
|
||||
DelegatorAddr sdk.Address `json:"delegator_addr"`
|
||||
ValidatorAddr sdk.Address `json:"validator_addr"`
|
||||
Shares string `json:"shares"`
|
||||
}
|
||||
|
||||
|
@ -184,12 +175,12 @@ func NewMsgUnbond(delegatorAddr, validatorAddr sdk.Address, shares string) MsgUn
|
|||
}
|
||||
|
||||
//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} }
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgUnbond) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
b, err := msgCdc.MarshalJSON(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ var (
|
|||
coinNegNotAtoms = sdk.Coin{"foo", -10000}
|
||||
)
|
||||
|
||||
// test ValidateBasic for MsgDeclareCandidacy
|
||||
func TestMsgDeclareCandidacy(t *testing.T) {
|
||||
// test ValidateBasic for MsgCreateValidator
|
||||
func TestMsgCreateValidator(t *testing.T) {
|
||||
tests := []struct {
|
||||
name, moniker, identity, website, details string
|
||||
validatorAddr sdk.Address
|
||||
|
@ -40,7 +40,7 @@ func TestMsgDeclareCandidacy(t *testing.T) {
|
|||
|
||||
for _, tc := range tests {
|
||||
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 {
|
||||
assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||
} else {
|
||||
|
@ -49,8 +49,8 @@ func TestMsgDeclareCandidacy(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// test ValidateBasic for MsgEditCandidacy
|
||||
func TestMsgEditCandidacy(t *testing.T) {
|
||||
// test ValidateBasic for MsgEditValidator
|
||||
func TestMsgEditValidator(t *testing.T) {
|
||||
tests := []struct {
|
||||
name, moniker, identity, website, details string
|
||||
validatorAddr sdk.Address
|
||||
|
@ -64,7 +64,7 @@ func TestMsgEditCandidacy(t *testing.T) {
|
|||
|
||||
for _, tc := range tests {
|
||||
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
|
||||
msg := NewMsgEditCandidacy(tc.validatorAddr, description)
|
||||
msg := NewMsgEditValidator(tc.validatorAddr, description)
|
||||
if tc.expectPass {
|
||||
assert.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
|
||||
} else {
|
||||
|
@ -139,8 +139,8 @@ func TestMsgUnbond(t *testing.T) {
|
|||
//tests := []struct {
|
||||
//tx sdk.Msg
|
||||
//}{
|
||||
//{NewMsgDeclareCandidacy(addrs[0], pks[0], bond, Description{})},
|
||||
//{NewMsgEditCandidacy(addrs[0], Description{})},
|
||||
//{NewMsgCreateValidator(addrs[0], pks[0], bond, Description{})},
|
||||
//{NewMsgEditValidator(addrs[0], Description{})},
|
||||
//{NewMsgDelegate(addrs[0], addrs[1], bond)},
|
||||
//{NewMsgUnbond(addrs[0], addrs[1], strconv.Itoa(bondAmt))},
|
||||
//}
|
||||
|
|
|
@ -18,12 +18,13 @@ type Params struct {
|
|||
}
|
||||
|
||||
func (p Params) equal(p2 Params) bool {
|
||||
bz1 := cdcEmpty.MustMarshalBinary(&p)
|
||||
bz2 := cdcEmpty.MustMarshalBinary(&p2)
|
||||
bz1 := msgCdc.MustMarshalBinary(&p)
|
||||
bz2 := msgCdc.MustMarshalBinary(&p2)
|
||||
return bytes.Equal(bz1, bz2)
|
||||
}
|
||||
|
||||
func defaultParams() Params {
|
||||
// default params
|
||||
func DefaultParams() Params {
|
||||
return Params{
|
||||
InflationRateChange: sdk.NewRat(13, 100),
|
||||
InflationMax: sdk.NewRat(20, 100),
|
||||
|
|
|
@ -25,13 +25,13 @@ type Pool struct {
|
|||
}
|
||||
|
||||
func (p Pool) equal(p2 Pool) bool {
|
||||
bz1 := cdcEmpty.MustMarshalBinary(&p)
|
||||
bz2 := cdcEmpty.MustMarshalBinary(&p2)
|
||||
bz1 := msgCdc.MustMarshalBinary(&p)
|
||||
bz2 := msgCdc.MustMarshalBinary(&p2)
|
||||
return bytes.Equal(bz1, bz2)
|
||||
}
|
||||
|
||||
// initial pool for testing
|
||||
func initialPool() Pool {
|
||||
func InitialPool() Pool {
|
||||
return Pool{
|
||||
LooseUnbondedTokens: 0,
|
||||
BondedTokens: 0,
|
||||
|
|
|
@ -44,8 +44,8 @@ func makeTestCodec() *wire.Codec {
|
|||
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
|
||||
cdc.RegisterConcrete(bank.MsgSend{}, "test/stake/Send", nil)
|
||||
cdc.RegisterConcrete(bank.MsgIssue{}, "test/stake/Issue", nil)
|
||||
cdc.RegisterConcrete(MsgDeclareCandidacy{}, "test/stake/DeclareCandidacy", nil)
|
||||
cdc.RegisterConcrete(MsgEditCandidacy{}, "test/stake/EditCandidacy", nil)
|
||||
cdc.RegisterConcrete(MsgCreateValidator{}, "test/stake/CreateValidator", nil)
|
||||
cdc.RegisterConcrete(MsgEditValidator{}, "test/stake/EditValidator", nil)
|
||||
cdc.RegisterConcrete(MsgUnbond{}, "test/stake/Unbond", nil)
|
||||
|
||||
// Register AppAccount
|
||||
|
@ -89,8 +89,8 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
|
|||
)
|
||||
ck := bank.NewKeeper(accountMapper)
|
||||
keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace)
|
||||
keeper.setPool(ctx, initialPool())
|
||||
keeper.setNewParams(ctx, defaultParams())
|
||||
keeper.setPool(ctx, InitialPool())
|
||||
keeper.setNewParams(ctx, DefaultParams())
|
||||
|
||||
// fill all the addresses with some coins
|
||||
for _, addr := range addrs {
|
||||
|
@ -120,7 +120,7 @@ func testAddr(addr string, bech string) sdk.Address {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bechexpected, err := sdk.Bech32CosmosifyAcc(res)
|
||||
bechexpected, err := sdk.Bech32ifyAcc(res)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ func testAddr(addr string, bech string) sdk.Address {
|
|||
panic("Bech encoding doesn't match reference")
|
||||
}
|
||||
|
||||
bechres, err := sdk.GetAccAddressBech32Cosmos(bech)
|
||||
bechres, err := sdk.GetAccAddressBech32(bech)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue