Merge remote-tracking branch 'origin/develop' into rigel/spec-staking
This commit is contained in:
commit
14c1ff27f3
|
@ -27,12 +27,6 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
make get_vendor_deps
|
make get_vendor_deps
|
||||||
- run:
|
|
||||||
name: linter
|
|
||||||
command: |
|
|
||||||
export PATH="$GOBIN:$PATH"
|
|
||||||
go get -u github.com/tendermint/lint/golint
|
|
||||||
go get -u github.com/alecthomas/gometalinter
|
|
||||||
- run:
|
- run:
|
||||||
name: binaries
|
name: binaries
|
||||||
command: |
|
command: |
|
||||||
|
@ -63,6 +57,12 @@ jobs:
|
||||||
key: v1-pkg-cache
|
key: v1-pkg-cache
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
key: v1-tree-{{ .Environment.CIRCLE_SHA1 }}
|
||||||
|
- run:
|
||||||
|
name: Get metalinter
|
||||||
|
command: |
|
||||||
|
export PATH="$GOBIN:$PATH"
|
||||||
|
go get -u github.com/tendermint/lint/golint
|
||||||
|
go get -u github.com/alecthomas/gometalinter
|
||||||
- run:
|
- run:
|
||||||
name: Lint source
|
name: Lint source
|
||||||
command: |
|
command: |
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
<!-- Thanks for filing a PR! Before hitting the button, please check the following items.-->
|
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
|
||||||
|
v ✰ Thanks for creating a PR! ✰
|
||||||
|
v Before smashing the submit button please review the checkboxes.
|
||||||
|
v If a checkbox is n/a - please still include it but + a little note why
|
||||||
|
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > -->
|
||||||
|
|
||||||
* [ ] Updated all relevant documentation in docs
|
* [ ] Updated all relevant documentation in docs
|
||||||
* [ ] Updated all code comments where relevant
|
* [ ] Updated all code comments where relevant
|
||||||
* [ ] Wrote tests
|
* [ ] Wrote tests
|
||||||
* [ ] Updated CHANGELOG.md
|
* [ ] Updated CHANGELOG.md
|
||||||
* [ ] Updated Basecoin / other examples
|
* [ ] Updated Gaia/Examples
|
||||||
* [ ] Squashed related commits and prefixed with PR number per [coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)
|
* [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr))
|
||||||
|
|
|
@ -14,6 +14,7 @@ docs/_build
|
||||||
# Data - ideally these don't exist
|
# Data - ideally these don't exist
|
||||||
examples/basecoin/app/data
|
examples/basecoin/app/data
|
||||||
baseapp/data/*
|
baseapp/data/*
|
||||||
|
client/lcd/keys/*
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
coverage.txt
|
coverage.txt
|
||||||
|
|
126
CHANGELOG.md
126
CHANGELOG.md
|
@ -1,45 +1,38 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## Pending
|
## 0.20.0
|
||||||
|
|
||||||
|
*TBD*
|
||||||
|
|
||||||
BREAKING CHANGES
|
BREAKING CHANGES
|
||||||
* [cli] rearranged commands under subcommands
|
* Change default ports from 466xx to 266xx
|
||||||
* [stake] remove Tick and add EndBlocker
|
|
||||||
|
## 0.19.0
|
||||||
|
|
||||||
|
*June 13, 2018*
|
||||||
|
|
||||||
|
BREAKING CHANGES
|
||||||
|
* msg.GetSignBytes() now returns bech32-encoded addresses in all cases
|
||||||
|
* [lcd] REST end-points now include gas
|
||||||
|
|
||||||
FEATURES
|
FEATURES
|
||||||
|
* [x/auth] Added AccountNumbers to BaseAccount and StdTxs to allow for replay protection with account pruning
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
* bank module uses go-wire codec instead of 'encoding/json'
|
* export command now writes current validator set for Tendermint
|
||||||
* auth module uses go-wire codec instead of 'encoding/json'
|
* [tests] Application module tests now use a mock application
|
||||||
* revised use of endblock and beginblock
|
* [gaiacli] Fix error message when account isn't found when running gaiacli account
|
||||||
|
* [lcd] refactored to eliminate use of global variables, and interdependent tests
|
||||||
|
* [x/stake] More stake tests added to test ByPower index
|
||||||
|
|
||||||
FIXES
|
FIXES
|
||||||
* [cli] fixed cli-bash tests
|
* Fixes consensus fault on testnet - see postmortem [here](https://github.com/cosmos/cosmos-sdk/issues/1197#issuecomment-396823021)
|
||||||
* [ci] added cli-bash tests
|
* [x/stake] bonded inflation removed, non-bonded inflation partially implemented
|
||||||
* [basecoin] updated basecoin for stake and slashing
|
* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs
|
||||||
* [docs] fixed references to old cli commands
|
* [lcd] fixed tx indexing/querying
|
||||||
|
* [cli] Added `--gas` flag to specify transaction gas limit
|
||||||
## 0.18.1
|
* [gaia] Registered slashing message handler
|
||||||
|
* [x/slashing] Set signInfo.StartHeight correctly for newly bonded validators
|
||||||
BREAKING CHANGES
|
|
||||||
|
|
||||||
* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes:
|
|
||||||
* StdTx (and its related stuff i.e. StdSignDoc, etc)
|
|
||||||
* StdFee
|
|
||||||
* StdSignature
|
|
||||||
* Account interface
|
|
||||||
* Related to this organization, I also:
|
|
||||||
* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module)
|
|
||||||
* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper
|
|
||||||
* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature)
|
|
||||||
* [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types
|
|
||||||
* Switch to bech32cosmos on all human readable inputs and outputs
|
|
||||||
|
|
||||||
BUG FIXES
|
|
||||||
|
|
||||||
* auto-sequencing transactions correctly
|
|
||||||
* query sequence via account store
|
|
||||||
* fixed duplicate pub_key in stake.Validator
|
|
||||||
|
|
||||||
FEATURES
|
FEATURES
|
||||||
* [docs] Reorganize documentation
|
* [docs] Reorganize documentation
|
||||||
|
@ -47,6 +40,8 @@ FEATURES
|
||||||
|
|
||||||
## 0.18.0
|
## 0.18.0
|
||||||
|
|
||||||
|
*June 9, 2018*
|
||||||
|
|
||||||
BREAKING CHANGES
|
BREAKING CHANGES
|
||||||
|
|
||||||
* [stake] candidate -> validator throughout (details in refactor comment)
|
* [stake] candidate -> validator throughout (details in refactor comment)
|
||||||
|
@ -64,6 +59,20 @@ BREAKING CHANGES
|
||||||
* Introduction of Unbonding fields, lowlevel logic throughout (not fully implemented with queue)
|
* Introduction of Unbonding fields, lowlevel logic throughout (not fully implemented with queue)
|
||||||
* Introduction of PoolShares type within validators,
|
* Introduction of PoolShares type within validators,
|
||||||
replaces three rational fields (BondedShares, UnbondingShares, UnbondedShares
|
replaces three rational fields (BondedShares, UnbondingShares, UnbondedShares
|
||||||
|
* [x/auth] move stuff specific to auth anteHandler to the auth module rather than the types folder. This includes:
|
||||||
|
* StdTx (and its related stuff i.e. StdSignDoc, etc)
|
||||||
|
* StdFee
|
||||||
|
* StdSignature
|
||||||
|
* Account interface
|
||||||
|
* Related to this organization, I also:
|
||||||
|
* [x/auth] got rid of AccountMapper interface (in favor of the struct already in auth module)
|
||||||
|
* [x/auth] removed the FeeHandler function from the AnteHandler, Replaced with FeeKeeper
|
||||||
|
* [x/auth] Removed GetSignatures() from Tx interface (as different Tx styles might use something different than StdSignature)
|
||||||
|
* [store] Removed SubspaceIterator and ReverseSubspaceIterator from KVStore interface and replaced them with helper functions in /types
|
||||||
|
* [cli] rearranged commands under subcommands
|
||||||
|
* [stake] remove Tick and add EndBlocker
|
||||||
|
* Switch to bech32cosmos on all human readable inputs and outputs
|
||||||
|
|
||||||
|
|
||||||
FEATURES
|
FEATURES
|
||||||
|
|
||||||
|
@ -80,12 +89,60 @@ FEATURES
|
||||||
* [stake] Added REST API
|
* [stake] Added REST API
|
||||||
* [Makefile] Added terraform/ansible playbooks to easily create remote testnets on Digital Ocean
|
* [Makefile] Added terraform/ansible playbooks to easily create remote testnets on Digital Ocean
|
||||||
|
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
|
||||||
* Auto-sequencing now works correctly
|
|
||||||
* [stake] staking delegator shares exchange rate now relative to equivalent-bonded-tokens the validator has instead of bonded tokens
|
* [stake] staking delegator shares exchange rate now relative to equivalent-bonded-tokens the validator has instead of bonded tokens
|
||||||
^ this is important for unbonded validators in the power store!
|
^ this is important for unbonded validators in the power store!
|
||||||
|
* [cli] fixed cli-bash tests
|
||||||
|
* [ci] added cli-bash tests
|
||||||
|
* [basecoin] updated basecoin for stake and slashing
|
||||||
|
* [docs] fixed references to old cli commands
|
||||||
* [docs] Downgraded Swagger to v2 for downstream compatibility
|
* [docs] Downgraded Swagger to v2 for downstream compatibility
|
||||||
|
* auto-sequencing transactions correctly
|
||||||
|
* query sequence via account store
|
||||||
|
* fixed duplicate pub_key in stake.Validator
|
||||||
|
* Auto-sequencing now works correctly
|
||||||
|
* [gaiacli] Fix error message when account isn't found when running gaiacli account
|
||||||
|
|
||||||
|
|
||||||
|
## 0.17.5
|
||||||
|
|
||||||
|
*June 5, 2018*
|
||||||
|
|
||||||
|
Update to Tendermint v0.19.9 (Fix evidence reactor, mempool deadlock, WAL panic,
|
||||||
|
memory leak)
|
||||||
|
|
||||||
|
## 0.17.4
|
||||||
|
|
||||||
|
*May 31, 2018*
|
||||||
|
|
||||||
|
Update to Tendermint v0.19.7 (WAL fixes and more)
|
||||||
|
|
||||||
|
## 0.17.3
|
||||||
|
|
||||||
|
*May 29, 2018*
|
||||||
|
|
||||||
|
Update to Tendermint v0.19.6 (fix fast-sync halt)
|
||||||
|
|
||||||
|
## 0.17.5
|
||||||
|
|
||||||
|
*June 5, 2018*
|
||||||
|
|
||||||
|
Update to Tendermint v0.19.9 (Fix evidence reactor, mempool deadlock, WAL panic,
|
||||||
|
memory leak)
|
||||||
|
|
||||||
|
## 0.17.4
|
||||||
|
|
||||||
|
*May 31, 2018*
|
||||||
|
|
||||||
|
Update to Tendermint v0.19.7 (WAL fixes and more)
|
||||||
|
|
||||||
|
## 0.17.3
|
||||||
|
|
||||||
|
*May 29, 2018*
|
||||||
|
|
||||||
|
Update to Tendermint v0.19.6 (fix fast-sync halt)
|
||||||
|
|
||||||
## 0.17.2
|
## 0.17.2
|
||||||
|
|
||||||
|
@ -125,6 +182,7 @@ BUG FIXES
|
||||||
|
|
||||||
* Auto-sequencing now works correctly
|
* Auto-sequencing now works correctly
|
||||||
|
|
||||||
|
|
||||||
## 0.16.0 (May 14th, 2018)
|
## 0.16.0 (May 14th, 2018)
|
||||||
|
|
||||||
BREAKING CHANGES
|
BREAKING CHANGES
|
||||||
|
@ -159,12 +217,14 @@ BUG FIXES
|
||||||
|
|
||||||
* Gaia now uses stake, ported from github.com/cosmos/gaia
|
* Gaia now uses stake, ported from github.com/cosmos/gaia
|
||||||
|
|
||||||
|
|
||||||
## 0.15.1 (April 29, 2018)
|
## 0.15.1 (April 29, 2018)
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
|
|
||||||
* Update Tendermint to v0.19.1 (includes many rpc fixes)
|
* Update Tendermint to v0.19.1 (includes many rpc fixes)
|
||||||
|
|
||||||
|
|
||||||
## 0.15.0 (April 29, 2018)
|
## 0.15.0 (April 29, 2018)
|
||||||
|
|
||||||
NOTE: v0.15.0 is a large breaking change that updates the encoding scheme to use
|
NOTE: v0.15.0 is a large breaking change that updates the encoding scheme to use
|
||||||
|
|
|
@ -170,8 +170,8 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/pelletier/go-toml"
|
name = "github.com/pelletier/go-toml"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
|
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
||||||
version = "v1.1.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/pkg/errors"
|
name = "github.com/pkg/errors"
|
||||||
|
@ -197,8 +197,8 @@
|
||||||
".",
|
".",
|
||||||
"mem"
|
"mem"
|
||||||
]
|
]
|
||||||
revision = "63644898a8da0bc22138abf860edaf5277b6102e"
|
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
|
||||||
version = "v1.1.0"
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/spf13/cast"
|
name = "github.com/spf13/cast"
|
||||||
|
@ -236,8 +236,8 @@
|
||||||
"assert",
|
"assert",
|
||||||
"require"
|
"require"
|
||||||
]
|
]
|
||||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
|
||||||
version = "v1.2.1"
|
version = "v1.2.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -256,7 +256,7 @@
|
||||||
"leveldb/table",
|
"leveldb/table",
|
||||||
"leveldb/util"
|
"leveldb/util"
|
||||||
]
|
]
|
||||||
revision = "5d6fca44a948d2be89a9702de7717f0168403d3d"
|
revision = "e2150783cd35f5b607daca48afd8c57ec54cc995"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/abci"
|
name = "github.com/tendermint/abci"
|
||||||
|
@ -267,8 +267,8 @@
|
||||||
"server",
|
"server",
|
||||||
"types"
|
"types"
|
||||||
]
|
]
|
||||||
revision = "9af8b7a7c87478869f8c280ed9539470b8f470b4"
|
revision = "198dccf0ddfd1bb176f87657e3286a05a6ed9540"
|
||||||
version = "v0.11.0-rc4"
|
version = "v0.12.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -330,6 +330,7 @@
|
||||||
"p2p/conn",
|
"p2p/conn",
|
||||||
"p2p/pex",
|
"p2p/pex",
|
||||||
"p2p/upnp",
|
"p2p/upnp",
|
||||||
|
"privval",
|
||||||
"proxy",
|
"proxy",
|
||||||
"rpc/client",
|
"rpc/client",
|
||||||
"rpc/core",
|
"rpc/core",
|
||||||
|
@ -344,11 +345,9 @@
|
||||||
"state/txindex/kv",
|
"state/txindex/kv",
|
||||||
"state/txindex/null",
|
"state/txindex/null",
|
||||||
"types",
|
"types",
|
||||||
"types/priv_validator",
|
|
||||||
"version"
|
"version"
|
||||||
]
|
]
|
||||||
revision = "b5baab0238c9ec26e3b2d229b0243f9ff9220bdb"
|
revision = "696e8c6f9e950eec15f150f314d2dd9ddf6bc601"
|
||||||
version = "v0.20.0-rc3"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "develop"
|
branch = "develop"
|
||||||
|
@ -366,7 +365,7 @@
|
||||||
"merkle",
|
"merkle",
|
||||||
"merkle/tmhash"
|
"merkle/tmhash"
|
||||||
]
|
]
|
||||||
revision = "44f1bdb0d55cc6527e38d0a7aab406e2580f56a4"
|
revision = "0c98d10b4ffbd87978d79c160e835b3d3df241ec"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -382,7 +381,7 @@
|
||||||
"ripemd160",
|
"ripemd160",
|
||||||
"salsa20/salsa"
|
"salsa20/salsa"
|
||||||
]
|
]
|
||||||
revision = "5ba7f63082460102a45837dbd1827e10f9479ac0"
|
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -396,13 +395,13 @@
|
||||||
"internal/timeseries",
|
"internal/timeseries",
|
||||||
"trace"
|
"trace"
|
||||||
]
|
]
|
||||||
revision = "1e491301e022f8f977054da4c2d852decd59571f"
|
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["unix"]
|
packages = ["unix"]
|
||||||
revision = "c11f84a56e43e20a78cee75a7c034031ecf57d1f"
|
revision = "bff228c7b664c5fce602223a05fb708fd8654986"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
|
@ -463,6 +462,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "ccb2ab7644a38c2d0326280582f758256e37fc98c3ef0403581e3b85cff42188"
|
inputs-digest = "d02a24bcfd8bded901e1b154e19b81ff797d3921046ede19d1d11eed61e871e7"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/abci"
|
name = "github.com/tendermint/abci"
|
||||||
version = "=0.11.0-rc4"
|
version = "=0.12.0"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/go-crypto"
|
name = "github.com/tendermint/go-crypto"
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/tendermint"
|
name = "github.com/tendermint/tendermint"
|
||||||
version = "=0.20.0-rc3"
|
revision = "696e8c6f9e950eec15f150f314d2dd9ddf6bc601"
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/tendermint/tmlibs"
|
name = "github.com/tendermint/tmlibs"
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -46,6 +46,9 @@ install_examples:
|
||||||
go install $(BUILD_FLAGS) ./examples/democoin/cmd/democoind
|
go install $(BUILD_FLAGS) ./examples/democoin/cmd/democoind
|
||||||
go install $(BUILD_FLAGS) ./examples/democoin/cmd/democli
|
go install $(BUILD_FLAGS) ./examples/democoin/cmd/democli
|
||||||
|
|
||||||
|
install_debug:
|
||||||
|
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiadebug
|
||||||
|
|
||||||
dist:
|
dist:
|
||||||
@bash publish/dist.sh
|
@bash publish/dist.sh
|
||||||
@bash publish/publish.sh
|
@bash publish/publish.sh
|
||||||
|
@ -92,6 +95,9 @@ test_cli:
|
||||||
test_unit:
|
test_unit:
|
||||||
@go test $(PACKAGES_NOCLITEST)
|
@go test $(PACKAGES_NOCLITEST)
|
||||||
|
|
||||||
|
test_race:
|
||||||
|
@go test -race $(PACKAGES_NOCLITEST)
|
||||||
|
|
||||||
test_cover:
|
test_cover:
|
||||||
@bash tests/test_cover.sh
|
@bash tests/test_cover.sh
|
||||||
|
|
||||||
|
@ -154,4 +160,4 @@ remotenet-status:
|
||||||
# To avoid unintended conflicts with file names, always add to .PHONY
|
# To avoid unintended conflicts with file names, always add to .PHONY
|
||||||
# unless there is a reason not to.
|
# unless there is a reason not to.
|
||||||
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
|
||||||
.PHONY: build build_examples install install_examples dist check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update remotenet-start remotenet-stop remotenet-status
|
.PHONY: build build_examples install install_examples install_debug dist check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update remotenet-start remotenet-stop remotenet-status
|
||||||
|
|
|
@ -18,6 +18,14 @@ master | [![CircleCI](https://circleci.com/gh/cosmos/cosmos-sdk/tree/master.s
|
||||||
|
|
||||||
**Note**: Requires [Go 1.10+](https://golang.org/dl/)
|
**Note**: Requires [Go 1.10+](https://golang.org/dl/)
|
||||||
|
|
||||||
|
## Testnet
|
||||||
|
|
||||||
|
For more information on connecting to the testnet, see
|
||||||
|
[cmd/gaia/testnets](/cmd/gaia/testnets)
|
||||||
|
|
||||||
|
For the latest status of the testnet, see the [status
|
||||||
|
file](/cmd/gaia/testnets/STATUS.md).
|
||||||
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,7 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error {
|
||||||
// TODO: we don't actually need the main store here
|
// TODO: we don't actually need the main store here
|
||||||
main := app.cms.GetKVStore(mainKey)
|
main := app.cms.GetKVStore(mainKey)
|
||||||
if main == nil {
|
if main == nil {
|
||||||
return errors.New("BaseApp expects MultiStore with 'main' KVStore")
|
return errors.New("baseapp expects MultiStore with 'main' KVStore")
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: Do we really need the header? What does it have that we want
|
// XXX: Do we really need the header? What does it have that we want
|
||||||
|
@ -216,11 +216,11 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error {
|
||||||
}
|
}
|
||||||
err := proto.Unmarshal(headerBytes, &header)
|
err := proto.Unmarshal(headerBytes, &header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed to parse Header")
|
return errors.Wrap(err, "failed to parse Header")
|
||||||
}
|
}
|
||||||
lastVersion := lastCommitID.Version
|
lastVersion := lastCommitID.Version
|
||||||
if header.Height != lastVersion {
|
if header.Height != lastVersion {
|
||||||
errStr := fmt.Sprintf("Expected db://%s.Height %v but got %v", dbHeaderKey, lastVersion, header.Height)
|
errStr := fmt.Sprintf("expected db://%s.Height %v but got %v", dbHeaderKey, lastVersion, header.Height)
|
||||||
return errors.New(errStr)
|
return errors.New(errStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -468,10 +468,10 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
switch r.(type) {
|
switch r.(type) {
|
||||||
case sdk.ErrorOutOfGas:
|
case sdk.ErrorOutOfGas:
|
||||||
log := fmt.Sprintf("Out of gas in location: %v", r.(sdk.ErrorOutOfGas).Descriptor)
|
log := fmt.Sprintf("out of gas in location: %v", r.(sdk.ErrorOutOfGas).Descriptor)
|
||||||
result = sdk.ErrOutOfGas(log).Result()
|
result = sdk.ErrOutOfGas(log).Result()
|
||||||
default:
|
default:
|
||||||
log := fmt.Sprintf("Recovered: %v\nstack:\n%v", r, string(debug.Stack()))
|
log := fmt.Sprintf("recovered: %v\nstack:\n%v", r, string(debug.Stack()))
|
||||||
result = sdk.ErrInternal(log).Result()
|
result = sdk.ErrInternal(log).Result()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
func RunForever(app abci.Application) {
|
func RunForever(app abci.Application) {
|
||||||
|
|
||||||
// Start the ABCI server
|
// Start the ABCI server
|
||||||
srv, err := server.NewServer("0.0.0.0:46658", "socket", app)
|
srv, err := server.NewServer("0.0.0.0:26658", "socket", app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmn.Exit(err.Error())
|
cmn.Exit(err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,12 @@ func (ctx CoreContext) BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit,
|
||||||
}
|
}
|
||||||
|
|
||||||
if res.CheckTx.Code != uint32(0) {
|
if res.CheckTx.Code != uint32(0) {
|
||||||
return res, errors.Errorf("CheckTx failed: (%d) %s",
|
return res, errors.Errorf("checkTx failed: (%d) %s",
|
||||||
res.CheckTx.Code,
|
res.CheckTx.Code,
|
||||||
res.CheckTx.Log)
|
res.CheckTx.Log)
|
||||||
}
|
}
|
||||||
if res.DeliverTx.Code != uint32(0) {
|
if res.DeliverTx.Code != uint32(0) {
|
||||||
return res, errors.Errorf("DeliverTx failed: (%d) %s",
|
return res, errors.Errorf("deliverTx failed: (%d) %s",
|
||||||
res.DeliverTx.Code,
|
res.DeliverTx.Code,
|
||||||
res.DeliverTx.Log)
|
res.DeliverTx.Log)
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res [
|
||||||
}
|
}
|
||||||
resp := result.Response
|
resp := result.Response
|
||||||
if resp.Code != uint32(0) {
|
if resp.Code != uint32(0) {
|
||||||
return res, errors.Errorf("Query failed: (%d) %s", resp.Code, resp.Log)
|
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
|
||||||
}
|
}
|
||||||
return resp.Value, nil
|
return resp.Value, nil
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ func (ctx CoreContext) GetFromAddress() (from sdk.Address, err error) {
|
||||||
|
|
||||||
info, err := keybase.Get(name)
|
info, err := keybase.Get(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Errorf("No key for: %s", name)
|
return nil, errors.Errorf("no key for: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return info.PubKey.Address(), nil
|
return info.PubKey.Address(), nil
|
||||||
|
@ -107,14 +107,17 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w
|
||||||
// build the Sign Messsage from the Standard Message
|
// build the Sign Messsage from the Standard Message
|
||||||
chainID := ctx.ChainID
|
chainID := ctx.ChainID
|
||||||
if chainID == "" {
|
if chainID == "" {
|
||||||
return nil, errors.Errorf("Chain ID required but not specified")
|
return nil, errors.Errorf("chain ID required but not specified")
|
||||||
}
|
}
|
||||||
|
accnum := ctx.AccountNumber
|
||||||
sequence := ctx.Sequence
|
sequence := ctx.Sequence
|
||||||
|
|
||||||
signMsg := auth.StdSignMsg{
|
signMsg := auth.StdSignMsg{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
Sequences: []int64{sequence},
|
AccountNumbers: []int64{accnum},
|
||||||
Msg: msg,
|
Sequences: []int64{sequence},
|
||||||
Fee: auth.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas?
|
Msg: msg,
|
||||||
|
Fee: auth.NewStdFee(ctx.Gas, sdk.Coin{}), // TODO run simulate to estimate gas?
|
||||||
}
|
}
|
||||||
|
|
||||||
keybase, err := keys.GetKeyBase()
|
keybase, err := keys.GetKeyBase()
|
||||||
|
@ -130,9 +133,10 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sigs := []auth.StdSignature{{
|
sigs := []auth.StdSignature{{
|
||||||
PubKey: pubkey,
|
PubKey: pubkey,
|
||||||
Signature: sig,
|
Signature: sig,
|
||||||
Sequence: sequence,
|
AccountNumber: accnum,
|
||||||
|
Sequence: sequence,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// marshal bytes
|
// marshal bytes
|
||||||
|
@ -144,6 +148,10 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w
|
||||||
// sign and build the transaction from the msg
|
// sign and build the transaction from the msg
|
||||||
func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) {
|
func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) {
|
||||||
|
|
||||||
|
ctx, err = EnsureAccountNumber(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// default to next sequence number if none provided
|
// default to next sequence number if none provided
|
||||||
ctx, err = EnsureSequence(ctx)
|
ctx, err = EnsureSequence(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -164,12 +172,36 @@ func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msg sdk.Msg, cdc *w
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the next sequence for the account address
|
// get the next sequence for the account address
|
||||||
func (ctx CoreContext) NextSequence(address []byte) (int64, error) {
|
func (ctx CoreContext) GetAccountNumber(address []byte) (int64, error) {
|
||||||
if ctx.Decoder == nil {
|
if ctx.Decoder == nil {
|
||||||
return 0, errors.New("AccountDecoder required but not provided")
|
return 0, errors.New("accountDecoder required but not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := ctx.Query(address, ctx.AccountStore)
|
res, err := ctx.Query(auth.AddressStoreKey(address), ctx.AccountStore)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) == 0 {
|
||||||
|
fmt.Printf("No account found. Returning 0.\n")
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := ctx.Decoder(res)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return account.GetAccountNumber(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the next sequence for the account address
|
||||||
|
func (ctx CoreContext) NextSequence(address []byte) (int64, error) {
|
||||||
|
if ctx.Decoder == nil {
|
||||||
|
return 0, errors.New("accountDecoder required but not provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := ctx.Query(auth.AddressStoreKey(address), ctx.AccountStore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -197,7 +229,7 @@ func (ctx CoreContext) GetPassphraseFromStdin(name string) (pass string, err err
|
||||||
// GetNode prepares a simple rpc.Client
|
// GetNode prepares a simple rpc.Client
|
||||||
func (ctx CoreContext) GetNode() (rpcclient.Client, error) {
|
func (ctx CoreContext) GetNode() (rpcclient.Client, error) {
|
||||||
if ctx.Client == nil {
|
if ctx.Client == nil {
|
||||||
return nil, errors.New("Must define node URI")
|
return nil, errors.New("must define node URI")
|
||||||
}
|
}
|
||||||
return ctx.Client, nil
|
return ctx.Client, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,11 @@ import (
|
||||||
type CoreContext struct {
|
type CoreContext struct {
|
||||||
ChainID string
|
ChainID string
|
||||||
Height int64
|
Height int64
|
||||||
|
Gas int64
|
||||||
TrustNode bool
|
TrustNode bool
|
||||||
NodeURI string
|
NodeURI string
|
||||||
FromAddressName string
|
FromAddressName string
|
||||||
|
AccountNumber int64
|
||||||
Sequence int64
|
Sequence int64
|
||||||
Client rpcclient.Client
|
Client rpcclient.Client
|
||||||
Decoder auth.AccountDecoder
|
Decoder auth.AccountDecoder
|
||||||
|
@ -31,6 +33,12 @@ func (c CoreContext) WithHeight(height int64) CoreContext {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithGas - return a copy of the context with an updated gas
|
||||||
|
func (c CoreContext) WithGas(gas int64) CoreContext {
|
||||||
|
c.Gas = gas
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// WithTrustNode - return a copy of the context with an updated TrustNode flag
|
// WithTrustNode - return a copy of the context with an updated TrustNode flag
|
||||||
func (c CoreContext) WithTrustNode(trustNode bool) CoreContext {
|
func (c CoreContext) WithTrustNode(trustNode bool) CoreContext {
|
||||||
c.TrustNode = trustNode
|
c.TrustNode = trustNode
|
||||||
|
@ -50,6 +58,12 @@ func (c CoreContext) WithFromAddressName(fromAddressName string) CoreContext {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithSequence - return a copy of the context with an account number
|
||||||
|
func (c CoreContext) WithAccountNumber(accnum int64) CoreContext {
|
||||||
|
c.AccountNumber = accnum
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// WithSequence - return a copy of the context with an updated sequence number
|
// WithSequence - return a copy of the context with an updated sequence number
|
||||||
func (c CoreContext) WithSequence(sequence int64) CoreContext {
|
func (c CoreContext) WithSequence(sequence int64) CoreContext {
|
||||||
c.Sequence = sequence
|
c.Sequence = sequence
|
||||||
|
|
|
@ -30,9 +30,11 @@ func NewCoreContextFromViper() CoreContext {
|
||||||
return CoreContext{
|
return CoreContext{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
Height: viper.GetInt64(client.FlagHeight),
|
Height: viper.GetInt64(client.FlagHeight),
|
||||||
|
Gas: viper.GetInt64(client.FlagGas),
|
||||||
TrustNode: viper.GetBool(client.FlagTrustNode),
|
TrustNode: viper.GetBool(client.FlagTrustNode),
|
||||||
FromAddressName: viper.GetString(client.FlagName),
|
FromAddressName: viper.GetString(client.FlagName),
|
||||||
NodeURI: nodeURI,
|
NodeURI: nodeURI,
|
||||||
|
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
|
||||||
Sequence: viper.GetInt64(client.FlagSequence),
|
Sequence: viper.GetInt64(client.FlagSequence),
|
||||||
Client: rpc,
|
Client: rpc,
|
||||||
Decoder: nil,
|
Decoder: nil,
|
||||||
|
@ -53,6 +55,25 @@ func defaultChainID() (string, error) {
|
||||||
return doc.ChainID, nil
|
return doc.ChainID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnsureSequence - automatically set sequence number if none provided
|
||||||
|
func EnsureAccountNumber(ctx CoreContext) (CoreContext, error) {
|
||||||
|
// Should be viper.IsSet, but this does not work - https://github.com/spf13/viper/pull/331
|
||||||
|
if viper.GetInt64(client.FlagAccountNumber) != 0 {
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
from, err := ctx.GetFromAddress()
|
||||||
|
if err != nil {
|
||||||
|
return ctx, err
|
||||||
|
}
|
||||||
|
accnum, err := ctx.GetAccountNumber(from)
|
||||||
|
if err != nil {
|
||||||
|
return ctx, err
|
||||||
|
}
|
||||||
|
fmt.Printf("Defaulting to account number: %d\n", accnum)
|
||||||
|
ctx = ctx.WithAccountNumber(accnum)
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
// EnsureSequence - automatically set sequence number if none provided
|
// EnsureSequence - automatically set sequence number if none provided
|
||||||
func EnsureSequence(ctx CoreContext) (CoreContext, error) {
|
func EnsureSequence(ctx CoreContext) (CoreContext, error) {
|
||||||
// Should be viper.IsSet, but this does not work - https://github.com/spf13/viper/pull/331
|
// Should be viper.IsSet, but this does not work - https://github.com/spf13/viper/pull/331
|
||||||
|
|
|
@ -4,13 +4,15 @@ import "github.com/spf13/cobra"
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
const (
|
const (
|
||||||
FlagChainID = "chain-id"
|
FlagChainID = "chain-id"
|
||||||
FlagNode = "node"
|
FlagNode = "node"
|
||||||
FlagHeight = "height"
|
FlagHeight = "height"
|
||||||
FlagTrustNode = "trust-node"
|
FlagGas = "gas"
|
||||||
FlagName = "name"
|
FlagTrustNode = "trust-node"
|
||||||
FlagSequence = "sequence"
|
FlagName = "name"
|
||||||
FlagFee = "fee"
|
FlagAccountNumber = "account-number"
|
||||||
|
FlagSequence = "sequence"
|
||||||
|
FlagFee = "fee"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LineBreak can be included in a command list to provide a blank line
|
// LineBreak can be included in a command list to provide a blank line
|
||||||
|
@ -23,7 +25,7 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
// TODO: make this default false when we support proofs
|
// TODO: make this default false when we support proofs
|
||||||
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for responses")
|
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for responses")
|
||||||
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
|
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
|
||||||
c.Flags().String(FlagNode, "tcp://localhost:46657", "<host>:<port> to tendermint rpc interface for this chain")
|
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
|
||||||
c.Flags().Int64(FlagHeight, 0, "block height to query, omit to get most recent provable block")
|
c.Flags().Int64(FlagHeight, 0, "block height to query, omit to get most recent provable block")
|
||||||
}
|
}
|
||||||
return cmds
|
return cmds
|
||||||
|
@ -33,10 +35,12 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
for _, c := range cmds {
|
for _, c := range cmds {
|
||||||
c.Flags().String(FlagName, "", "Name of private key with which to sign")
|
c.Flags().String(FlagName, "", "Name of private key with which to sign")
|
||||||
|
c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
|
||||||
c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx")
|
c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx")
|
||||||
c.Flags().String(FlagFee, "", "Fee to pay along with transaction")
|
c.Flags().String(FlagFee, "", "Fee to pay along with transaction")
|
||||||
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
|
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
|
||||||
c.Flags().String(FlagNode, "tcp://localhost:46657", "<host>:<port> to tendermint rpc interface for this chain")
|
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
|
||||||
|
c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction")
|
||||||
}
|
}
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if len(pass) < MinPassLength {
|
if len(pass) < MinPassLength {
|
||||||
return "", errors.Errorf("Password must be at least %d characters", MinPassLength)
|
return "", errors.Errorf("password must be at least %d characters", MinPassLength)
|
||||||
}
|
}
|
||||||
return pass, nil
|
return pass, nil
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func GetCheckPassword(prompt, prompt2 string, buf *bufio.Reader) (string, error)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if pass != pass2 {
|
if pass != pass2 {
|
||||||
return "", errors.New("Passphrases don't match")
|
return "", errors.New("passphrases don't match")
|
||||||
}
|
}
|
||||||
return pass, nil
|
return pass, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
|
||||||
name = "inmemorykey"
|
name = "inmemorykey"
|
||||||
} else {
|
} else {
|
||||||
if len(args) != 1 || len(args[0]) == 0 {
|
if len(args) != 1 || len(args[0]) == 0 {
|
||||||
return errors.New("You must provide a name for the key")
|
return errors.New("you must provide a name for the key")
|
||||||
}
|
}
|
||||||
name = args[0]
|
name = args[0]
|
||||||
kb, err = GetKeyBase()
|
kb, err = GetKeyBase()
|
||||||
|
@ -102,12 +102,6 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// addOutput lets us json format the data
|
|
||||||
type addOutput struct {
|
|
||||||
Key keys.Info `json:"key"`
|
|
||||||
Seed string `json:"seed"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func printCreate(info keys.Info, seed string) {
|
func printCreate(info keys.Info, seed string) {
|
||||||
output := viper.Get(cli.OutputFlag)
|
output := viper.Get(cli.OutputFlag)
|
||||||
switch output {
|
switch output {
|
||||||
|
@ -121,7 +115,10 @@ func printCreate(info keys.Info, seed string) {
|
||||||
fmt.Println(seed)
|
fmt.Println(seed)
|
||||||
}
|
}
|
||||||
case "json":
|
case "json":
|
||||||
out := addOutput{Key: info}
|
out, err := Bech32KeyOutput(info)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
if !viper.GetBool(flagNoBackup) {
|
if !viper.GetBool(flagNoBackup) {
|
||||||
out.Seed = seed
|
out.Seed = seed
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,9 +53,11 @@ func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Write([]byte("[]"))
|
w.Write([]byte("[]"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keysOutput := make([]KeyOutput, len(infos))
|
keysOutput, err := Bech32KeysOutput(infos)
|
||||||
for i, info := range infos {
|
if err != nil {
|
||||||
keysOutput[i] = KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address().Bytes())}
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
output, err := json.MarshalIndent(keysOutput, "", " ")
|
output, err := json.MarshalIndent(keysOutput, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
keys "github.com/tendermint/go-crypto/keys"
|
keys "github.com/tendermint/go-crypto/keys"
|
||||||
|
|
||||||
|
@ -51,7 +50,12 @@ func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
keyOutput := KeyOutput{Name: info.Name, Address: sdk.Address(info.PubKey.Address())}
|
keyOutput, err := Bech32KeyOutput(info)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
output, err := json.MarshalIndent(keyOutput, "", " ")
|
output, err := json.MarshalIndent(keyOutput, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
keys "github.com/tendermint/go-crypto/keys"
|
keys "github.com/tendermint/go-crypto/keys"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
|
@ -22,6 +21,8 @@ const KeyDBName = "keys"
|
||||||
// keybase is used to make GetKeyBase a singleton
|
// keybase is used to make GetKeyBase a singleton
|
||||||
var keybase keys.Keybase
|
var keybase keys.Keybase
|
||||||
|
|
||||||
|
// TODO make keybase take a database not load from the directory
|
||||||
|
|
||||||
// initialize a keybase based on the configuration
|
// initialize a keybase based on the configuration
|
||||||
func GetKeyBase() (keys.Keybase, error) {
|
func GetKeyBase() (keys.Keybase, error) {
|
||||||
rootDir := viper.GetString(cli.HomeFlag)
|
rootDir := viper.GetString(cli.HomeFlag)
|
||||||
|
@ -47,29 +48,47 @@ func SetKeyBase(kb keys.Keybase) {
|
||||||
|
|
||||||
// used for outputting keys.Info over REST
|
// used for outputting keys.Info over REST
|
||||||
type KeyOutput struct {
|
type KeyOutput struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Address sdk.Address `json:"address"`
|
Address string `json:"address"`
|
||||||
PubKey crypto.PubKey `json:"pub_key"`
|
PubKey string `json:"pub_key"`
|
||||||
|
Seed string `json:"seed,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewKeyOutput(info keys.Info) KeyOutput {
|
// create a list of KeyOutput in bech32 format
|
||||||
return KeyOutput{
|
func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) {
|
||||||
Name: info.Name,
|
|
||||||
Address: sdk.Address(info.PubKey.Address().Bytes()),
|
|
||||||
PubKey: info.PubKey,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewKeyOutputs(infos []keys.Info) []KeyOutput {
|
|
||||||
kos := make([]KeyOutput, len(infos))
|
kos := make([]KeyOutput, len(infos))
|
||||||
for i, info := range infos {
|
for i, info := range infos {
|
||||||
kos[i] = NewKeyOutput(info)
|
ko, err := Bech32KeyOutput(info)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
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) {
|
func printInfo(info keys.Info) {
|
||||||
ko := NewKeyOutput(info)
|
ko, err := Bech32KeyOutput(info)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
switch viper.Get(cli.OutputFlag) {
|
switch viper.Get(cli.OutputFlag) {
|
||||||
case "text":
|
case "text":
|
||||||
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
||||||
|
@ -84,7 +103,10 @@ func printInfo(info keys.Info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printInfos(infos []keys.Info) {
|
func printInfos(infos []keys.Info) {
|
||||||
kos := NewKeyOutputs(infos)
|
kos, err := Bech32KeysOutput(infos)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
switch viper.Get(cli.OutputFlag) {
|
switch viper.Get(cli.OutputFlag) {
|
||||||
case "text":
|
case "text":
|
||||||
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
fmt.Printf("NAME:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
|
||||||
|
@ -101,13 +123,5 @@ func printInfos(infos []keys.Info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func printKeyOutput(ko KeyOutput) {
|
func printKeyOutput(ko KeyOutput) {
|
||||||
bechAccount, err := sdk.Bech32ifyAcc(ko.Address)
|
fmt.Printf("%s\t%s\t%s\n", ko.Name, ko.Address, ko.PubKey)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
bechPubKey, err := sdk.Bech32ifyAccPub(ko.PubKey)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fmt.Printf("%s\t%s\t%s\n", ko.Name, bechAccount, bechPubKey)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
package lcd
|
|
||||||
|
|
||||||
// NOTE: COPIED VERBATIM FROM tendermint/tendermint/rpc/test/helpers.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
|
||||||
|
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
var globalConfig *cfg.Config
|
|
||||||
|
|
||||||
// f**ing long, but unique for each test
|
|
||||||
func makePathname() string {
|
|
||||||
// get path
|
|
||||||
p, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
// fmt.Println(p)
|
|
||||||
sep := string(filepath.Separator)
|
|
||||||
return strings.Replace(p, sep, "_", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func randPort() int {
|
|
||||||
return int(cmn.RandUint16()/2 + 10000)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeAddrs() (string, string, string) {
|
|
||||||
start := randPort()
|
|
||||||
return fmt.Sprintf("tcp://0.0.0.0:%d", start),
|
|
||||||
fmt.Sprintf("tcp://0.0.0.0:%d", start+1),
|
|
||||||
fmt.Sprintf("tcp://0.0.0.0:%d", start+2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetConfig returns a config for the test cases as a singleton
|
|
||||||
func GetConfig() *cfg.Config {
|
|
||||||
if globalConfig == nil {
|
|
||||||
pathname := makePathname()
|
|
||||||
globalConfig = cfg.ResetTestRoot(pathname)
|
|
||||||
|
|
||||||
// and we use random ports to run in parallel
|
|
||||||
tm, rpc, _ := makeAddrs()
|
|
||||||
globalConfig.P2P.ListenAddress = tm
|
|
||||||
globalConfig.RPC.ListenAddress = rpc
|
|
||||||
globalConfig.TxIndex.IndexTags = "app.creator" // see kvstore application
|
|
||||||
}
|
|
||||||
return globalConfig
|
|
||||||
}
|
|
|
@ -1,142 +1,115 @@
|
||||||
package lcd
|
package lcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
cryptoKeys "github.com/tendermint/go-crypto/keys"
|
cryptoKeys "github.com/tendermint/go-crypto/keys"
|
||||||
tmcfg "github.com/tendermint/tendermint/config"
|
|
||||||
nm "github.com/tendermint/tendermint/node"
|
|
||||||
p2p "github.com/tendermint/tendermint/p2p"
|
p2p "github.com/tendermint/tendermint/p2p"
|
||||||
"github.com/tendermint/tendermint/proxy"
|
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
|
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
|
||||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
|
||||||
"github.com/tendermint/tmlibs/cli"
|
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
|
||||||
"github.com/tendermint/tmlibs/log"
|
|
||||||
|
|
||||||
client "github.com/cosmos/cosmos-sdk/client"
|
client "github.com/cosmos/cosmos-sdk/client"
|
||||||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
|
||||||
tests "github.com/cosmos/cosmos-sdk/tests"
|
tests "github.com/cosmos/cosmos-sdk/tests"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
)
|
stakerest "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||||
|
|
||||||
var (
|
|
||||||
coinDenom = "steak"
|
|
||||||
coinAmount = int64(10000000)
|
|
||||||
|
|
||||||
validatorAddr1 = ""
|
|
||||||
validatorAddr2 = ""
|
|
||||||
|
|
||||||
// XXX bad globals
|
|
||||||
name = "test"
|
|
||||||
password = "0123456789"
|
|
||||||
port string
|
|
||||||
seed string
|
|
||||||
sendAddr string
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestKeys(t *testing.T) {
|
func TestKeys(t *testing.T) {
|
||||||
|
name, password := "test", "1234567890"
|
||||||
// empty keys
|
addr, seed := CreateAddr(t, "test", password, GetKB(t))
|
||||||
// XXX: the test comes with a key setup
|
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
|
||||||
/*
|
defer cleanup()
|
||||||
res, body := request(t, port, "GET", "/keys", nil)
|
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
|
||||||
assert.Equal(t, "[]", body, "Expected an empty array")
|
|
||||||
*/
|
|
||||||
|
|
||||||
// get seed
|
// get seed
|
||||||
res, body := request(t, port, "GET", "/keys/seed", nil)
|
res, body := Request(t, port, "GET", "/keys/seed", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
newSeed := body
|
newSeed := body
|
||||||
reg, err := regexp.Compile(`([a-z]+ ){12}`)
|
reg, err := regexp.Compile(`([a-z]+ ){12}`)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
match := reg.MatchString(seed)
|
match := reg.MatchString(seed)
|
||||||
assert.True(t, match, "Returned seed has wrong foramt", seed)
|
assert.True(t, match, "Returned seed has wrong format", seed)
|
||||||
|
|
||||||
newName := "test_newname"
|
newName := "test_newname"
|
||||||
newPassword := "0987654321"
|
newPassword := "0987654321"
|
||||||
|
|
||||||
// add key
|
// add key
|
||||||
var jsonStr = []byte(fmt.Sprintf(`{"name":"test_fail", "password":"%s"}`, password))
|
var jsonStr = []byte(fmt.Sprintf(`{"name":"test_fail", "password":"%s"}`, password))
|
||||||
res, body = request(t, port, "POST", "/keys", jsonStr)
|
res, body = Request(t, port, "POST", "/keys", jsonStr)
|
||||||
|
|
||||||
assert.Equal(t, http.StatusBadRequest, res.StatusCode, "Account creation should require a seed")
|
assert.Equal(t, http.StatusBadRequest, res.StatusCode, "Account creation should require a seed")
|
||||||
|
|
||||||
jsonStr = []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed": "%s"}`, newName, newPassword, newSeed))
|
jsonStr = []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed": "%s"}`, newName, newPassword, newSeed))
|
||||||
res, body = request(t, port, "POST", "/keys", jsonStr)
|
res, body = Request(t, port, "POST", "/keys", jsonStr)
|
||||||
|
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
addr := body
|
addr2 := body
|
||||||
assert.Len(t, addr, 40, "Returned address has wrong format", addr)
|
assert.Len(t, addr2, 40, "Returned address has wrong format", addr2)
|
||||||
|
|
||||||
// existing keys
|
// existing keys
|
||||||
res, body = request(t, port, "GET", "/keys", nil)
|
res, body = Request(t, port, "GET", "/keys", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
var m [2]keys.KeyOutput
|
var m [2]keys.KeyOutput
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &m)
|
err = cdc.UnmarshalJSON([]byte(body), &m)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
sendAddrAcc, _ := sdk.GetAccAddressHex(sendAddr)
|
addr2Acc, err := sdk.GetAccAddressHex(addr2)
|
||||||
addrAcc, _ := sdk.GetAccAddressHex(addr)
|
require.Nil(t, err)
|
||||||
|
addr2Bech32 := sdk.MustBech32ifyAcc(addr2Acc)
|
||||||
|
addrBech32 := sdk.MustBech32ifyAcc(addr)
|
||||||
|
|
||||||
assert.Equal(t, m[0].Name, name, "Did not serve keys name correctly")
|
assert.Equal(t, name, m[0].Name, "Did not serve keys name correctly")
|
||||||
assert.Equal(t, m[0].Address, sendAddrAcc, "Did not serve keys Address correctly")
|
assert.Equal(t, addrBech32, m[0].Address, "Did not serve keys Address correctly")
|
||||||
assert.Equal(t, m[1].Name, newName, "Did not serve keys name correctly")
|
assert.Equal(t, newName, m[1].Name, "Did not serve keys name correctly")
|
||||||
assert.Equal(t, m[1].Address, addrAcc, "Did not serve keys Address correctly")
|
assert.Equal(t, addr2Bech32, m[1].Address, "Did not serve keys Address correctly")
|
||||||
|
|
||||||
// select key
|
// select key
|
||||||
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
|
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
|
||||||
res, body = request(t, port, "GET", keyEndpoint, nil)
|
res, body = Request(t, port, "GET", keyEndpoint, nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
var m2 keys.KeyOutput
|
var m2 keys.KeyOutput
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &m2)
|
err = cdc.UnmarshalJSON([]byte(body), &m2)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
|
assert.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
|
||||||
assert.Equal(t, addrAcc, m2.Address, "Did not serve keys Address correctly")
|
assert.Equal(t, addr2Bech32, m2.Address, "Did not serve keys Address correctly")
|
||||||
|
|
||||||
// update key
|
// update key
|
||||||
jsonStr = []byte(fmt.Sprintf(`{"old_password":"%s", "new_password":"12345678901"}`, newPassword))
|
jsonStr = []byte(fmt.Sprintf(`{
|
||||||
res, body = request(t, port, "PUT", keyEndpoint, jsonStr)
|
"old_password":"%s",
|
||||||
|
"new_password":"12345678901"
|
||||||
|
}`, newPassword))
|
||||||
|
|
||||||
|
res, body = Request(t, port, "PUT", keyEndpoint, jsonStr)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
// here it should say unauthorized as we changed the password before
|
// here it should say unauthorized as we changed the password before
|
||||||
res, body = request(t, port, "PUT", keyEndpoint, jsonStr)
|
res, body = Request(t, port, "PUT", keyEndpoint, jsonStr)
|
||||||
require.Equal(t, http.StatusUnauthorized, res.StatusCode, body)
|
require.Equal(t, http.StatusUnauthorized, res.StatusCode, body)
|
||||||
|
|
||||||
// delete key
|
// delete key
|
||||||
jsonStr = []byte(`{"password":"12345678901"}`)
|
jsonStr = []byte(`{"password":"12345678901"}`)
|
||||||
res, body = request(t, port, "DELETE", keyEndpoint, jsonStr)
|
res, body = Request(t, port, "DELETE", keyEndpoint, jsonStr)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVersion(t *testing.T) {
|
func TestVersion(t *testing.T) {
|
||||||
|
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
// node info
|
// node info
|
||||||
res, body := request(t, port, "GET", "/version", nil)
|
res, body := Request(t, port, "GET", "/version", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
reg, err := regexp.Compile(`\d+\.\d+\.\d+(-dev)?`)
|
reg, err := regexp.Compile(`\d+\.\d+\.\d+(-dev)?`)
|
||||||
|
@ -146,9 +119,11 @@ func TestVersion(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeStatus(t *testing.T) {
|
func TestNodeStatus(t *testing.T) {
|
||||||
|
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
// node info
|
// node info
|
||||||
res, body := request(t, port, "GET", "/node_info", nil)
|
res, body := Request(t, port, "GET", "/node_info", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
var nodeInfo p2p.NodeInfo
|
var nodeInfo p2p.NodeInfo
|
||||||
|
@ -158,21 +133,20 @@ func TestNodeStatus(t *testing.T) {
|
||||||
assert.NotEqual(t, p2p.NodeInfo{}, nodeInfo, "res: %v", res)
|
assert.NotEqual(t, p2p.NodeInfo{}, nodeInfo, "res: %v", res)
|
||||||
|
|
||||||
// syncing
|
// syncing
|
||||||
res, body = request(t, port, "GET", "/syncing", nil)
|
res, body = Request(t, port, "GET", "/syncing", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
// we expect that there is no other node running so the syncing state is "false"
|
// we expect that there is no other node running so the syncing state is "false"
|
||||||
// we c
|
|
||||||
assert.Equal(t, "false", body)
|
assert.Equal(t, "false", body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBlock(t *testing.T) {
|
func TestBlock(t *testing.T) {
|
||||||
|
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
|
||||||
tests.WaitForHeight(2, port)
|
defer cleanup()
|
||||||
|
|
||||||
var resultBlock ctypes.ResultBlock
|
var resultBlock ctypes.ResultBlock
|
||||||
|
|
||||||
res, body := request(t, port, "GET", "/blocks/latest", nil)
|
res, body := Request(t, port, "GET", "/blocks/latest", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
err := cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||||
|
@ -182,7 +156,7 @@ func TestBlock(t *testing.T) {
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
res, body = request(t, port, "GET", "/blocks/1", nil)
|
res, body = Request(t, port, "GET", "/blocks/1", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
err = json.Unmarshal([]byte(body), &resultBlock)
|
err = json.Unmarshal([]byte(body), &resultBlock)
|
||||||
|
@ -192,50 +166,62 @@ func TestBlock(t *testing.T) {
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
res, body = request(t, port, "GET", "/blocks/1000000000", nil)
|
res, body = Request(t, port, "GET", "/blocks/1000000000", nil)
|
||||||
require.Equal(t, http.StatusNotFound, res.StatusCode, body)
|
require.Equal(t, http.StatusNotFound, res.StatusCode, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidators(t *testing.T) {
|
func TestValidators(t *testing.T) {
|
||||||
|
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.Address{})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
var resultVals ctypes.ResultValidators
|
var resultVals rpc.ResultValidatorsOutput
|
||||||
|
|
||||||
res, body := request(t, port, "GET", "/validatorsets/latest", nil)
|
res, body := Request(t, port, "GET", "/validatorsets/latest", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &resultVals)
|
err := cdc.UnmarshalJSON([]byte(body), &resultVals)
|
||||||
require.Nil(t, err, "Couldn't parse validatorset")
|
require.Nil(t, err, "Couldn't parse validatorset")
|
||||||
|
|
||||||
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals)
|
assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
|
||||||
|
|
||||||
|
assert.Contains(t, resultVals.Validators[0].Address, "cosmosvaladdr")
|
||||||
|
assert.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub")
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
res, body = request(t, port, "GET", "/validatorsets/1", nil)
|
res, body = Request(t, port, "GET", "/validatorsets/1", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &resultVals)
|
err = cdc.UnmarshalJSON([]byte(body), &resultVals)
|
||||||
require.Nil(t, err, "Couldn't parse validatorset")
|
require.Nil(t, err, "Couldn't parse validatorset")
|
||||||
|
|
||||||
assert.NotEqual(t, ctypes.ResultValidators{}, resultVals)
|
assert.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
|
||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
res, body = request(t, port, "GET", "/validatorsets/1000000000", nil)
|
res, body = Request(t, port, "GET", "/validatorsets/1000000000", nil)
|
||||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCoinSend(t *testing.T) {
|
func TestCoinSend(t *testing.T) {
|
||||||
|
name, password := "test", "1234567890"
|
||||||
|
addr, seed := CreateAddr(t, "test", password, GetKB(t))
|
||||||
|
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
bz, err := hex.DecodeString("8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6")
|
||||||
|
require.NoError(t, err)
|
||||||
|
someFakeAddr := sdk.MustBech32ifyAcc(bz)
|
||||||
|
|
||||||
// query empty
|
// query empty
|
||||||
//res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil)
|
res, body := Request(t, port, "GET", "/accounts/"+someFakeAddr, nil)
|
||||||
res, body := request(t, port, "GET", "/accounts/8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6", nil)
|
|
||||||
require.Equal(t, http.StatusNoContent, res.StatusCode, body)
|
require.Equal(t, http.StatusNoContent, res.StatusCode, body)
|
||||||
|
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, port, addr)
|
||||||
initialBalance := acc.GetCoins()
|
initialBalance := acc.GetCoins()
|
||||||
|
|
||||||
// create TX
|
// create TX
|
||||||
receiveAddr, resultTx := doSend(t, port, seed)
|
receiveAddr, resultTx := doSend(t, port, seed, name, password, addr)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// check if tx was commited
|
// check if tx was commited
|
||||||
|
@ -243,27 +229,31 @@ func TestCoinSend(t *testing.T) {
|
||||||
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||||
|
|
||||||
// query sender
|
// query sender
|
||||||
acc = getAccount(t, sendAddr)
|
acc = getAccount(t, port, addr)
|
||||||
coins := acc.GetCoins()
|
coins := acc.GetCoins()
|
||||||
mycoins := coins[0]
|
mycoins := coins[0]
|
||||||
assert.Equal(t, coinDenom, mycoins.Denom)
|
assert.Equal(t, "steak", mycoins.Denom)
|
||||||
assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount)
|
assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount)
|
||||||
|
|
||||||
// query receiver
|
// query receiver
|
||||||
acc = getAccount(t, receiveAddr)
|
acc = getAccount(t, port, receiveAddr)
|
||||||
coins = acc.GetCoins()
|
coins = acc.GetCoins()
|
||||||
mycoins = coins[0]
|
mycoins = coins[0]
|
||||||
assert.Equal(t, coinDenom, mycoins.Denom)
|
assert.Equal(t, "steak", mycoins.Denom)
|
||||||
assert.Equal(t, int64(1), mycoins.Amount)
|
assert.Equal(t, int64(1), mycoins.Amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIBCTransfer(t *testing.T) {
|
func TestIBCTransfer(t *testing.T) {
|
||||||
|
name, password := "test", "1234567890"
|
||||||
|
addr, seed := CreateAddr(t, "test", password, GetKB(t))
|
||||||
|
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, port, addr)
|
||||||
initialBalance := acc.GetCoins()
|
initialBalance := acc.GetCoins()
|
||||||
|
|
||||||
// create TX
|
// create TX
|
||||||
resultTx := doIBCTransfer(t, port, seed)
|
resultTx := doIBCTransfer(t, port, seed, name, password, addr)
|
||||||
|
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
@ -272,72 +262,108 @@ func TestIBCTransfer(t *testing.T) {
|
||||||
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||||
|
|
||||||
// query sender
|
// query sender
|
||||||
acc = getAccount(t, sendAddr)
|
acc = getAccount(t, port, addr)
|
||||||
coins := acc.GetCoins()
|
coins := acc.GetCoins()
|
||||||
mycoins := coins[0]
|
mycoins := coins[0]
|
||||||
assert.Equal(t, coinDenom, mycoins.Denom)
|
assert.Equal(t, "steak", mycoins.Denom)
|
||||||
assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount)
|
assert.Equal(t, initialBalance[0].Amount-1, mycoins.Amount)
|
||||||
|
|
||||||
// TODO: query ibc egress packet state
|
// TODO: query ibc egress packet state
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTxs(t *testing.T) {
|
func TestTxs(t *testing.T) {
|
||||||
|
name, password := "test", "1234567890"
|
||||||
// TODO: re-enable once we can get txs by tag
|
addr, seed := CreateAddr(t, "test", password, GetKB(t))
|
||||||
|
cleanup, _, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
// query wrong
|
// query wrong
|
||||||
// res, body := request(t, port, "GET", "/txs", nil)
|
res, body := Request(t, port, "GET", "/txs", nil)
|
||||||
// require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
|
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
|
||||||
|
|
||||||
// query empty
|
// query empty
|
||||||
// res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=coin.sender='%s'", "8FA6AB57AD6870F6B5B2E57735F38F2F30E73CB6"), nil)
|
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3"), nil)
|
||||||
// require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
assert.Equal(t, "[]", body)
|
||||||
// assert.Equal(t, "[]", body)
|
|
||||||
|
|
||||||
// create TX
|
// create TX
|
||||||
_, resultTx := doSend(t, port, seed)
|
receiveAddr, resultTx := doSend(t, port, seed, name, password, addr)
|
||||||
|
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// check if tx is findable
|
// check if tx is findable
|
||||||
res, body := request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil)
|
res, body = Request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
// // query sender
|
type txInfo struct {
|
||||||
// res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=coin.sender='%s'", addr), nil)
|
Height int64 `json:"height"`
|
||||||
// require.Equal(t, http.StatusOK, res.StatusCode, body)
|
Tx sdk.Tx `json:"tx"`
|
||||||
|
Result abci.ResponseDeliverTx `json:"result"`
|
||||||
|
}
|
||||||
|
var indexedTxs []txInfo
|
||||||
|
|
||||||
// assert.NotEqual(t, "[]", body)
|
// check if tx is queryable
|
||||||
|
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=tx.hash='%s'", resultTx.Hash), nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
assert.NotEqual(t, "[]", body)
|
||||||
|
|
||||||
// // query receiver
|
err := cdc.UnmarshalJSON([]byte(body), &indexedTxs)
|
||||||
// res, body = request(t, port, "GET", fmt.Sprintf("/txs?tag=coin.receiver='%s'", receiveAddr), nil)
|
require.NoError(t, err)
|
||||||
// require.Equal(t, http.StatusOK, res.StatusCode, body)
|
assert.Equal(t, 1, len(indexedTxs))
|
||||||
|
|
||||||
// assert.NotEqual(t, "[]", body)
|
// query sender
|
||||||
|
addrBech := sdk.MustBech32ifyAcc(addr)
|
||||||
|
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", addrBech), nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
err = cdc.UnmarshalJSON([]byte(body), &indexedTxs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(indexedTxs), "%v", indexedTxs) // there are 2 txs created with doSend
|
||||||
|
assert.Equal(t, resultTx.Height, indexedTxs[0].Height)
|
||||||
|
|
||||||
|
// query recipient
|
||||||
|
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
|
||||||
|
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=recipient_bech32='%s'", receiveAddrBech), nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
|
err = cdc.UnmarshalJSON([]byte(body), &indexedTxs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(indexedTxs))
|
||||||
|
assert.Equal(t, resultTx.Height, indexedTxs[0].Height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidatorsQuery(t *testing.T) {
|
func TestValidatorsQuery(t *testing.T) {
|
||||||
validators := getValidators(t)
|
cleanup, pks, port := InitializeTestLCD(t, 2, []sdk.Address{})
|
||||||
|
require.Equal(t, 2, len(pks))
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
validators := getValidators(t, port)
|
||||||
assert.Equal(t, len(validators), 2)
|
assert.Equal(t, len(validators), 2)
|
||||||
|
|
||||||
// make sure all the validators were found (order unknown because sorted by owner addr)
|
// make sure all the validators were found (order unknown because sorted by owner addr)
|
||||||
foundVal1, foundVal2 := false, false
|
foundVal1, foundVal2 := false, false
|
||||||
res1, res2 := hex.EncodeToString(validators[0].Owner), hex.EncodeToString(validators[1].Owner)
|
pk1Bech := sdk.MustBech32ifyValPub(pks[0])
|
||||||
if res1 == validatorAddr1 || res2 == validatorAddr1 {
|
pk2Bech := sdk.MustBech32ifyValPub(pks[1])
|
||||||
|
if validators[0].PubKey == pk1Bech || validators[1].PubKey == pk1Bech {
|
||||||
foundVal1 = true
|
foundVal1 = true
|
||||||
}
|
}
|
||||||
if res1 == validatorAddr2 || res2 == validatorAddr2 {
|
if validators[0].PubKey == pk2Bech || validators[1].PubKey == pk2Bech {
|
||||||
foundVal2 = true
|
foundVal2 = true
|
||||||
}
|
}
|
||||||
assert.True(t, foundVal1, "validatorAddr1 %v, res1 %v, res2 %v", validatorAddr1, res1, res2)
|
assert.True(t, foundVal1, "pk1Bech %v, owner1 %v, owner2 %v", pk1Bech, validators[0].Owner, validators[1].Owner)
|
||||||
assert.True(t, foundVal2, "validatorAddr2 %v, res1 %v, res2 %v", validatorAddr2, res1, res2)
|
assert.True(t, foundVal2, "pk2Bech %v, owner1 %v, owner2 %v", pk2Bech, validators[0].Owner, validators[1].Owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBond(t *testing.T) {
|
func TestBonding(t *testing.T) {
|
||||||
|
name, password, denom := "test", "1234567890", "steak"
|
||||||
|
addr, seed := CreateAddr(t, "test", password, GetKB(t))
|
||||||
|
cleanup, pks, port := InitializeTestLCD(t, 2, []sdk.Address{addr})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
validator1Owner := pks[0].Address()
|
||||||
|
|
||||||
// create bond TX
|
// create bond TX
|
||||||
resultTx := doBond(t, port, seed)
|
resultTx := doBond(t, port, seed, name, password, addr, validator1Owner)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
// check if tx was commited
|
// check if tx was commited
|
||||||
|
@ -345,196 +371,42 @@ func TestBond(t *testing.T) {
|
||||||
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||||
|
|
||||||
// query sender
|
// query sender
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, port, addr)
|
||||||
coins := acc.GetCoins()
|
coins := acc.GetCoins()
|
||||||
assert.Equal(t, int64(87), coins.AmountOf(coinDenom))
|
assert.Equal(t, int64(40), coins.AmountOf(denom))
|
||||||
|
|
||||||
// query candidate
|
// query validator
|
||||||
bond := getDelegation(t, sendAddr, validatorAddr1)
|
bond := getDelegation(t, port, addr, validator1Owner)
|
||||||
assert.Equal(t, "10/1", bond.Shares.String())
|
assert.Equal(t, "60/1", bond.Shares.String())
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnbond(t *testing.T) {
|
//////////////////////
|
||||||
|
// testing unbonding
|
||||||
|
|
||||||
// create unbond TX
|
// create unbond TX
|
||||||
resultTx := doUnbond(t, port, seed)
|
resultTx = doUnbond(t, port, seed, name, password, addr, validator1Owner)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
// query validator
|
||||||
|
bond = getDelegation(t, port, addr, validator1Owner)
|
||||||
|
assert.Equal(t, "30/1", bond.Shares.String())
|
||||||
|
|
||||||
// check if tx was commited
|
// check if tx was commited
|
||||||
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||||
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
assert.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||||
|
|
||||||
|
// TODO fix shares fn in staking
|
||||||
// query sender
|
// query sender
|
||||||
acc := getAccount(t, sendAddr)
|
//acc := getAccount(t, sendAddr)
|
||||||
coins := acc.GetCoins()
|
//coins := acc.GetCoins()
|
||||||
assert.Equal(t, int64(98), coins.AmountOf(coinDenom))
|
//assert.Equal(t, int64(98), coins.AmountOf(coinDenom))
|
||||||
|
|
||||||
// query candidate
|
|
||||||
bond := getDelegation(t, sendAddr, validatorAddr1)
|
|
||||||
assert.Equal(t, "9/1", bond.Shares.String())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//__________________________________________________________
|
//_____________________________________________________________________________
|
||||||
// helpers
|
// get the account to get the sequence
|
||||||
|
func getAccount(t *testing.T, port string, addr sdk.Address) auth.Account {
|
||||||
// strt TM and the LCD in process, listening on their respective sockets
|
addrBech32 := sdk.MustBech32ifyAcc(addr)
|
||||||
func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
res, body := Request(t, port, "GET", "/accounts/"+addrBech32, nil)
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "lcd_test")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
viper.Set(cli.HomeFlag, dir)
|
|
||||||
kb, err := keys.GetKeyBase() // dbm.NewMemDB()) // :(
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
config := GetConfig()
|
|
||||||
config.Consensus.TimeoutCommit = 1000
|
|
||||||
config.Consensus.SkipTimeoutCommit = false
|
|
||||||
|
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
|
||||||
logger = log.NewFilter(logger, log.AllowError())
|
|
||||||
privValidatorFile := config.PrivValidatorFile()
|
|
||||||
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
|
|
||||||
db := dbm.NewMemDB()
|
|
||||||
app := gapp.NewGaiaApp(logger, db)
|
|
||||||
cdc = gapp.MakeCodec() // XXX
|
|
||||||
|
|
||||||
genesisFile := config.GenesisFile()
|
|
||||||
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
genDoc.Validators = append(genDoc.Validators,
|
|
||||||
tmtypes.GenesisValidator{
|
|
||||||
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
|
|
||||||
Power: 1,
|
|
||||||
Name: "val",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
pk1 := genDoc.Validators[0].PubKey
|
|
||||||
pk2 := genDoc.Validators[1].PubKey
|
|
||||||
validatorAddr1 = hex.EncodeToString(pk1.Address())
|
|
||||||
validatorAddr2 = hex.EncodeToString(pk2.Address())
|
|
||||||
|
|
||||||
// NOTE it's bad practice to reuse pk address for the owner address but doing in the
|
|
||||||
// test for simplicity
|
|
||||||
var appGenTxs [2]json.RawMessage
|
|
||||||
appGenTxs[0], _, _, err = gapp.GaiaAppGenTxNF(cdc, pk1, pk1.Address(), "test_val1", true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
appGenTxs[1], _, _, err = gapp.GaiaAppGenTxNF(cdc, pk2, pk2.Address(), "test_val2", true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
genesisState, err := gapp.GaiaAppGenState(cdc, appGenTxs[:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the sendAddr to genesis
|
|
||||||
var info cryptoKeys.Info
|
|
||||||
info, seed, err = kb.Create(name, password, cryptoKeys.AlgoEd25519) // XXX global seed
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
sendAddr = info.PubKey.Address().String() // XXX global
|
|
||||||
accAuth := auth.NewBaseAccountWithAddress(info.PubKey.Address())
|
|
||||||
accAuth.Coins = sdk.Coins{{"steak", 100}}
|
|
||||||
acc := gapp.NewGenesisAccount(&accAuth)
|
|
||||||
genesisState.Accounts = append(genesisState.Accounts, acc)
|
|
||||||
|
|
||||||
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
genDoc.AppStateJSON = appState
|
|
||||||
|
|
||||||
// LCD listen address
|
|
||||||
var listenAddr string
|
|
||||||
listenAddr, port, err = server.FreeTCPAddr()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: need to set this so LCD knows the tendermint node address!
|
|
||||||
viper.Set(client.FlagNode, config.RPC.ListenAddress)
|
|
||||||
viper.Set(client.FlagChainID, genDoc.ChainID)
|
|
||||||
|
|
||||||
node, err := startTM(config, logger, genDoc, privVal, app)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
lcd, err := startLCD(logger, listenAddr, cdc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tests.WaitForStart(port)
|
|
||||||
|
|
||||||
return node, lcd, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create & start in-process tendermint node with memdb
|
|
||||||
// and in-process abci application.
|
|
||||||
// TODO: need to clean up the WAL dir or enable it to be not persistent
|
|
||||||
func startTM(cfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, privVal tmtypes.PrivValidator, app abci.Application) (*nm.Node, error) {
|
|
||||||
genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil }
|
|
||||||
dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil }
|
|
||||||
n, err := nm.NewNode(cfg,
|
|
||||||
privVal,
|
|
||||||
proxy.NewLocalClientCreator(app),
|
|
||||||
genDocProvider,
|
|
||||||
dbProvider,
|
|
||||||
logger.With("module", "node"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = n.Start()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for rpc
|
|
||||||
tests.WaitForRPC(GetConfig().RPC.ListenAddress)
|
|
||||||
|
|
||||||
logger.Info("Tendermint running!")
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// start the LCD. note this blocks!
|
|
||||||
func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) {
|
|
||||||
handler := createHandler(cdc)
|
|
||||||
return tmrpc.StartHTTPServer(listenAddr, handler, logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
func request(t *testing.T, port, method, path string, payload []byte) (*http.Response, string) {
|
|
||||||
var res *http.Response
|
|
||||||
var err error
|
|
||||||
url := fmt.Sprintf("http://localhost:%v%v", port, path)
|
|
||||||
req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
|
|
||||||
require.Nil(t, err)
|
|
||||||
res, err = http.DefaultClient.Do(req)
|
|
||||||
// res, err = http.Post(url, "application/json", bytes.NewBuffer(payload))
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
output, err := ioutil.ReadAll(res.Body)
|
|
||||||
res.Body.Close()
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
return res, string(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAccount(t *testing.T, sendAddr string) auth.Account {
|
|
||||||
// get the account to get the sequence
|
|
||||||
res, body := request(t, port, "GET", "/accounts/"+sendAddr, nil)
|
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
var acc auth.Account
|
var acc auth.Account
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &acc)
|
err := cdc.UnmarshalJSON([]byte(body), &acc)
|
||||||
|
@ -542,20 +414,34 @@ func getAccount(t *testing.T, sendAddr string) auth.Account {
|
||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctypes.ResultBroadcastTxCommit) {
|
func doSend(t *testing.T, port, seed, name, password string, addr sdk.Address) (receiveAddr sdk.Address, resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
|
|
||||||
// create receive address
|
// create receive address
|
||||||
kb := client.MockKeyBase()
|
kb := client.MockKeyBase()
|
||||||
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
receiveAddr = receiveInfo.PubKey.Address().String()
|
receiveAddr = receiveInfo.PubKey.Address()
|
||||||
|
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
|
||||||
|
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, port, addr)
|
||||||
|
accnum := acc.GetAccountNumber()
|
||||||
sequence := acc.GetSequence()
|
sequence := acc.GetSequence()
|
||||||
|
|
||||||
// send
|
// send
|
||||||
jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", "sequence":%d, "amount":[{ "denom": "%s", "amount": 1 }] }`, name, password, sequence, coinDenom))
|
jsonStr := []byte(fmt.Sprintf(`{
|
||||||
res, body := request(t, port, "POST", "/accounts/"+receiveAddr+"/send", jsonStr)
|
"name":"%s",
|
||||||
|
"password":"%s",
|
||||||
|
"account_number":%d,
|
||||||
|
"sequence":%d,
|
||||||
|
"gas": 10000,
|
||||||
|
"amount":[
|
||||||
|
{
|
||||||
|
"denom": "%s",
|
||||||
|
"amount": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, name, password, accnum, sequence, "steak"))
|
||||||
|
res, body := Request(t, port, "POST", "/accounts/"+receiveAddrBech+"/send", jsonStr)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
|
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
|
||||||
|
@ -564,21 +450,34 @@ func doSend(t *testing.T, port, seed string) (receiveAddr string, resultTx ctype
|
||||||
return receiveAddr, resultTx
|
return receiveAddr, resultTx
|
||||||
}
|
}
|
||||||
|
|
||||||
func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
|
|
||||||
// create receive address
|
// create receive address
|
||||||
kb := client.MockKeyBase()
|
kb := client.MockKeyBase()
|
||||||
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
receiveInfo, _, err := kb.Create("receive_address", "1234567890", cryptoKeys.CryptoAlgo("ed25519"))
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
receiveAddr := receiveInfo.PubKey.Address().String()
|
receiveAddr := receiveInfo.PubKey.Address()
|
||||||
|
receiveAddrBech := sdk.MustBech32ifyAcc(receiveAddr)
|
||||||
|
|
||||||
// get the account to get the sequence
|
// get the account to get the sequence
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, port, addr)
|
||||||
|
accnum := acc.GetAccountNumber()
|
||||||
sequence := acc.GetSequence()
|
sequence := acc.GetSequence()
|
||||||
|
|
||||||
// send
|
// send
|
||||||
jsonStr := []byte(fmt.Sprintf(`{ "name":"%s", "password":"%s", "sequence":%d, "amount":[{ "denom": "%s", "amount": 1 }] }`, name, password, sequence, coinDenom))
|
jsonStr := []byte(fmt.Sprintf(`{
|
||||||
res, body := request(t, port, "POST", "/ibc/testchain/"+receiveAddr+"/send", jsonStr)
|
"name":"%s",
|
||||||
|
"password": "%s",
|
||||||
|
"account_number":%d,
|
||||||
|
"sequence": %d,
|
||||||
|
"gas": 100000,
|
||||||
|
"amount":[
|
||||||
|
{
|
||||||
|
"denom": "%s",
|
||||||
|
"amount": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`, name, password, accnum, sequence, "steak"))
|
||||||
|
res, body := Request(t, port, "POST", "/ibc/testchain/"+receiveAddrBech+"/send", jsonStr)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
|
err = cdc.UnmarshalJSON([]byte(body), &resultTx)
|
||||||
|
@ -587,9 +486,13 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad
|
||||||
return resultTx
|
return resultTx
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDelegation(t *testing.T, delegatorAddr, candidateAddr string) stake.Delegation {
|
func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.Address) stake.Delegation {
|
||||||
|
|
||||||
|
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
|
||||||
|
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
|
||||||
|
|
||||||
// get the account to get the sequence
|
// get the account to get the sequence
|
||||||
res, body := request(t, port, "GET", "/stake/"+delegatorAddr+"/bonding_status/"+candidateAddr, nil)
|
res, body := Request(t, port, "GET", "/stake/"+delegatorAddrBech+"/bonding_status/"+validatorAddrBech, nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
var bond stake.Delegation
|
var bond stake.Delegation
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &bond)
|
err := cdc.UnmarshalJSON([]byte(body), &bond)
|
||||||
|
@ -597,26 +500,32 @@ func getDelegation(t *testing.T, delegatorAddr, candidateAddr string) stake.Dele
|
||||||
return bond
|
return bond
|
||||||
}
|
}
|
||||||
|
|
||||||
func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
func doBond(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
// get the account to get the sequence
|
// get the account to get the sequence
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, port, delegatorAddr)
|
||||||
|
accnum := acc.GetAccountNumber()
|
||||||
sequence := acc.GetSequence()
|
sequence := acc.GetSequence()
|
||||||
|
|
||||||
|
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
|
||||||
|
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
|
||||||
|
|
||||||
// send
|
// send
|
||||||
jsonStr := []byte(fmt.Sprintf(`{
|
jsonStr := []byte(fmt.Sprintf(`{
|
||||||
"name": "%s",
|
"name": "%s",
|
||||||
"password": "%s",
|
"password": "%s",
|
||||||
|
"account_number": %d,
|
||||||
"sequence": %d,
|
"sequence": %d,
|
||||||
|
"gas": 10000,
|
||||||
"delegate": [
|
"delegate": [
|
||||||
{
|
{
|
||||||
"delegator_addr": "%x",
|
"delegator_addr": "%s",
|
||||||
"validator_addr": "%s",
|
"validator_addr": "%s",
|
||||||
"bond": { "denom": "%s", "amount": 10 }
|
"bond": { "denom": "%s", "amount": 60 }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"unbond": []
|
"unbond": []
|
||||||
}`, name, password, sequence, acc.GetAddress(), validatorAddr1, coinDenom))
|
}`, name, password, accnum, sequence, delegatorAddrBech, validatorAddrBech, "steak"))
|
||||||
res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
|
res, body := Request(t, port, "POST", "/stake/delegations", jsonStr)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
var results []ctypes.ResultBroadcastTxCommit
|
var results []ctypes.ResultBroadcastTxCommit
|
||||||
|
@ -626,26 +535,32 @@ func doBond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxC
|
||||||
return results[0]
|
return results[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastTxCommit) {
|
func doUnbond(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.Address) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||||
// get the account to get the sequence
|
// get the account to get the sequence
|
||||||
acc := getAccount(t, sendAddr)
|
acc := getAccount(t, port, delegatorAddr)
|
||||||
|
accnum := acc.GetAccountNumber()
|
||||||
sequence := acc.GetSequence()
|
sequence := acc.GetSequence()
|
||||||
|
|
||||||
|
delegatorAddrBech := sdk.MustBech32ifyAcc(delegatorAddr)
|
||||||
|
validatorAddrBech := sdk.MustBech32ifyVal(validatorAddr)
|
||||||
|
|
||||||
// send
|
// send
|
||||||
jsonStr := []byte(fmt.Sprintf(`{
|
jsonStr := []byte(fmt.Sprintf(`{
|
||||||
"name": "%s",
|
"name": "%s",
|
||||||
"password": "%s",
|
"password": "%s",
|
||||||
|
"account_number": %d,
|
||||||
"sequence": %d,
|
"sequence": %d,
|
||||||
"bond": [],
|
"gas": 10000,
|
||||||
|
"delegate": [],
|
||||||
"unbond": [
|
"unbond": [
|
||||||
{
|
{
|
||||||
"delegator_addr": "%x",
|
"delegator_addr": "%s",
|
||||||
"validator_addr": "%s",
|
"validator_addr": "%s",
|
||||||
"shares": "1"
|
"shares": "30"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}`, name, password, sequence, acc.GetAddress(), validatorAddr1))
|
}`, name, password, accnum, sequence, delegatorAddrBech, validatorAddrBech))
|
||||||
res, body := request(t, port, "POST", "/stake/delegations", jsonStr)
|
res, body := Request(t, port, "POST", "/stake/delegations", jsonStr)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
var results []ctypes.ResultBroadcastTxCommit
|
var results []ctypes.ResultBroadcastTxCommit
|
||||||
|
@ -655,11 +570,11 @@ func doUnbond(t *testing.T, port, seed string) (resultTx ctypes.ResultBroadcastT
|
||||||
return results[0]
|
return results[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func getValidators(t *testing.T) []stake.Validator {
|
func getValidators(t *testing.T, port string) []stakerest.StakeValidatorOutput {
|
||||||
// get the account to get the sequence
|
// get the account to get the sequence
|
||||||
res, body := request(t, port, "GET", "/stake/validators", nil)
|
res, body := Request(t, port, "GET", "/stake/validators", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
var validators stake.Validators
|
var validators []stakerest.StakeValidatorOutput
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &validators)
|
err := cdc.UnmarshalJSON([]byte(body), &validators)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
return validators
|
return validators
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
package lcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
nm "github.com/tendermint/tendermint/node"
|
|
||||||
)
|
|
||||||
|
|
||||||
var node *nm.Node
|
|
||||||
|
|
||||||
// See https://golang.org/pkg/testing/#hdr-Main
|
|
||||||
// for more details
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
// start a basecoind node and LCD server in the background to test against
|
|
||||||
|
|
||||||
// run all the tests against a single server instance
|
|
||||||
node, lcd, err := startTMAndLCD()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
code := m.Run()
|
|
||||||
|
|
||||||
// tear down
|
|
||||||
// TODO: cleanup
|
|
||||||
// TODO: it would be great if TM could run without
|
|
||||||
// persiting anything in the first place
|
|
||||||
node.Stop()
|
|
||||||
node.Wait()
|
|
||||||
|
|
||||||
// just a listener ...
|
|
||||||
lcd.Close()
|
|
||||||
|
|
||||||
os.Exit(code)
|
|
||||||
}
|
|
|
@ -25,48 +25,42 @@ import (
|
||||||
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
flagListenAddr = "laddr"
|
|
||||||
flagCORS = "cors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ServeCommand will generate a long-running rest server
|
// ServeCommand will generate a long-running rest server
|
||||||
// (aka Light Client Daemon) that exposes functionality similar
|
// (aka Light Client Daemon) that exposes functionality similar
|
||||||
// to the cli, but over rest
|
// to the cli, but over rest
|
||||||
func ServeCommand(cdc *wire.Codec) *cobra.Command {
|
func ServeCommand(cdc *wire.Codec) *cobra.Command {
|
||||||
|
flagListenAddr := "laddr"
|
||||||
|
flagCORS := "cors"
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "rest-server",
|
Use: "rest-server",
|
||||||
Short: "Start LCD (light-client daemon), a local REST server",
|
Short: "Start LCD (light-client daemon), a local REST server",
|
||||||
RunE: startRESTServerFn(cdc),
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
listenAddr := viper.GetString(flagListenAddr)
|
||||||
|
handler := createHandler(cdc)
|
||||||
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
|
||||||
|
With("module", "rest-server")
|
||||||
|
listener, err := tmserver.StartHTTPServer(listenAddr, handler, logger)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Info("REST server started")
|
||||||
|
|
||||||
|
// Wait forever and cleanup
|
||||||
|
cmn.TrapSignal(func() {
|
||||||
|
err := listener.Close()
|
||||||
|
logger.Error("error closing listener", "err", err)
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP(flagListenAddr, "a", "tcp://localhost:1317", "Address for server to listen on")
|
cmd.Flags().StringP(flagListenAddr, "a", "tcp://localhost:1317", "Address for server to listen on")
|
||||||
cmd.Flags().String(flagCORS, "", "Set to domains that can make CORS requests (* for all)")
|
cmd.Flags().String(flagCORS, "", "Set to domains that can make CORS requests (* for all)")
|
||||||
cmd.Flags().StringP(client.FlagChainID, "c", "", "ID of chain we connect to")
|
cmd.Flags().StringP(client.FlagChainID, "c", "", "ID of chain we connect to")
|
||||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func startRESTServerFn(cdc *wire.Codec) func(cmd *cobra.Command, args []string) error {
|
|
||||||
return func(cmd *cobra.Command, args []string) error {
|
|
||||||
listenAddr := viper.GetString(flagListenAddr)
|
|
||||||
handler := createHandler(cdc)
|
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
|
|
||||||
With("module", "rest-server")
|
|
||||||
listener, err := tmserver.StartHTTPServer(listenAddr, handler, logger)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
logger.Info("REST server started")
|
|
||||||
|
|
||||||
// Wait forever and cleanup
|
|
||||||
cmn.TrapSignal(func() {
|
|
||||||
err := listener.Close()
|
|
||||||
logger.Error("Error closing listener", "err", err)
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createHandler(cdc *wire.Codec) http.Handler {
|
func createHandler(cdc *wire.Codec) http.Handler {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/version", version.RequestHandler).Methods("GET")
|
r.HandleFunc("/version", version.RequestHandler).Methods("GET")
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
package lcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
crkeys "github.com/tendermint/go-crypto/keys"
|
||||||
|
tmcfg "github.com/tendermint/tendermint/config"
|
||||||
|
nm "github.com/tendermint/tendermint/node"
|
||||||
|
pvm "github.com/tendermint/tendermint/privval"
|
||||||
|
"github.com/tendermint/tendermint/proxy"
|
||||||
|
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
"github.com/tendermint/tmlibs/cli"
|
||||||
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
|
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
|
"github.com/cosmos/cosmos-sdk/tests"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// f**ing long, but unique for each test
|
||||||
|
func makePathname() string {
|
||||||
|
// get path
|
||||||
|
p, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
sep := string(filepath.Separator)
|
||||||
|
return strings.Replace(p, sep, "_", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfig returns a config for the test cases as a singleton
|
||||||
|
func GetConfig() *tmcfg.Config {
|
||||||
|
pathname := makePathname()
|
||||||
|
config := tmcfg.ResetTestRoot(pathname)
|
||||||
|
|
||||||
|
tmAddr, _, err := server.FreeTCPAddr()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
rcpAddr, _, err := server.FreeTCPAddr()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config.P2P.ListenAddress = tmAddr
|
||||||
|
config.RPC.ListenAddress = rcpAddr
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the lcd test keybase
|
||||||
|
// note can't use a memdb because the request is expecting to interact with the default location
|
||||||
|
func GetKB(t *testing.T) crkeys.Keybase {
|
||||||
|
dir, err := ioutil.TempDir("", "lcd_test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
viper.Set(cli.HomeFlag, dir)
|
||||||
|
keybase, err := keys.GetKeyBase() // dbm.NewMemDB()) // :(
|
||||||
|
require.NoError(t, err)
|
||||||
|
return keybase
|
||||||
|
}
|
||||||
|
|
||||||
|
// add an address to the store return name and password
|
||||||
|
func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (addr sdk.Address, seed string) {
|
||||||
|
var info crkeys.Info
|
||||||
|
var err error
|
||||||
|
info, seed, err = kb.Create(name, password, crkeys.AlgoEd25519)
|
||||||
|
require.NoError(t, err)
|
||||||
|
addr = info.PubKey.Address()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// strt TM and the LCD in process, listening on their respective sockets
|
||||||
|
// nValidators = number of validators
|
||||||
|
// initAddrs = accounts to initialize with some steaks
|
||||||
|
func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.Address) (cleanup func(), validatorsPKs []crypto.PubKey, port string) {
|
||||||
|
|
||||||
|
config := GetConfig()
|
||||||
|
config.Consensus.TimeoutCommit = 1000
|
||||||
|
config.Consensus.SkipTimeoutCommit = false
|
||||||
|
config.TxIndex.IndexAllTags = true
|
||||||
|
|
||||||
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||||
|
logger = log.NewFilter(logger, log.AllowError())
|
||||||
|
privValidatorFile := config.PrivValidatorFile()
|
||||||
|
privVal := pvm.LoadOrGenFilePV(privValidatorFile)
|
||||||
|
privVal.Reset()
|
||||||
|
db := dbm.NewMemDB()
|
||||||
|
app := gapp.NewGaiaApp(logger, db)
|
||||||
|
cdc = gapp.MakeCodec() // XXX
|
||||||
|
|
||||||
|
genesisFile := config.GenesisFile()
|
||||||
|
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// add more validators
|
||||||
|
if nValidators < 1 {
|
||||||
|
panic("InitializeTestLCD must use at least one validator")
|
||||||
|
}
|
||||||
|
for i := 1; i < nValidators; i++ {
|
||||||
|
genDoc.Validators = append(genDoc.Validators,
|
||||||
|
tmtypes.GenesisValidator{
|
||||||
|
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
|
||||||
|
Power: 1,
|
||||||
|
Name: "val",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE it's bad practice to reuse pk address for the owner address but doing in the
|
||||||
|
// test for simplicity
|
||||||
|
var appGenTxs []json.RawMessage
|
||||||
|
for _, gdValidator := range genDoc.Validators {
|
||||||
|
pk := gdValidator.PubKey
|
||||||
|
validatorsPKs = append(validatorsPKs, pk) // append keys for output
|
||||||
|
appGenTx, _, _, err := gapp.GaiaAppGenTxNF(cdc, pk, pk.Address(), "test_val1", true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
appGenTxs = append(appGenTxs, appGenTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
genesisState, err := gapp.GaiaAppGenState(cdc, appGenTxs[:])
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// add some tokens to init accounts
|
||||||
|
for _, addr := range initAddrs {
|
||||||
|
accAuth := auth.NewBaseAccountWithAddress(addr)
|
||||||
|
accAuth.Coins = sdk.Coins{{"steak", 100}}
|
||||||
|
acc := gapp.NewGenesisAccount(&accAuth)
|
||||||
|
genesisState.Accounts = append(genesisState.Accounts, acc)
|
||||||
|
}
|
||||||
|
|
||||||
|
appState, err := wire.MarshalJSONIndent(cdc, genesisState)
|
||||||
|
require.NoError(t, err)
|
||||||
|
genDoc.AppStateJSON = appState
|
||||||
|
|
||||||
|
// LCD listen address
|
||||||
|
var listenAddr string
|
||||||
|
listenAddr, port, err = server.FreeTCPAddr()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// XXX: need to set this so LCD knows the tendermint node address!
|
||||||
|
viper.Set(client.FlagNode, config.RPC.ListenAddress)
|
||||||
|
viper.Set(client.FlagChainID, genDoc.ChainID)
|
||||||
|
|
||||||
|
node, err := startTM(config, logger, genDoc, privVal, app)
|
||||||
|
require.NoError(t, err)
|
||||||
|
lcd, err := startLCD(logger, listenAddr, cdc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
//time.Sleep(time.Second)
|
||||||
|
//tests.WaitForHeight(2, port)
|
||||||
|
tests.WaitForStart(port)
|
||||||
|
tests.WaitForHeight(1, port)
|
||||||
|
|
||||||
|
// for use in defer
|
||||||
|
cleanup = func() {
|
||||||
|
node.Stop()
|
||||||
|
node.Wait()
|
||||||
|
lcd.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create & start in-process tendermint node with memdb
|
||||||
|
// and in-process abci application.
|
||||||
|
// TODO: need to clean up the WAL dir or enable it to be not persistent
|
||||||
|
func startTM(tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, privVal tmtypes.PrivValidator, app abci.Application) (*nm.Node, error) {
|
||||||
|
genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil }
|
||||||
|
dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil }
|
||||||
|
n, err := nm.NewNode(tmcfg,
|
||||||
|
privVal,
|
||||||
|
proxy.NewLocalClientCreator(app),
|
||||||
|
genDocProvider,
|
||||||
|
dbProvider,
|
||||||
|
logger.With("module", "node"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = n.Start()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for rpc
|
||||||
|
tests.WaitForRPC(tmcfg.RPC.ListenAddress)
|
||||||
|
|
||||||
|
logger.Info("Tendermint running!")
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the LCD. note this blocks!
|
||||||
|
func startLCD(logger log.Logger, listenAddr string, cdc *wire.Codec) (net.Listener, error) {
|
||||||
|
handler := createHandler(cdc)
|
||||||
|
return tmrpc.StartHTTPServer(listenAddr, handler, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make a test lcd test request
|
||||||
|
func Request(t *testing.T, port, method, path string, payload []byte) (*http.Response, string) {
|
||||||
|
var res *http.Response
|
||||||
|
var err error
|
||||||
|
url := fmt.Sprintf("http://localhost:%v%v", port, path)
|
||||||
|
req, err := http.NewRequest(method, url, bytes.NewBuffer(payload))
|
||||||
|
require.Nil(t, err)
|
||||||
|
res, err = http.DefaultClient.Do(req)
|
||||||
|
// res, err = http.Post(url, "application/json", bytes.NewBuffer(payload))
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
output, err := ioutil.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
return res, string(output)
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ func BlockCommand() *cobra.Command {
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
RunE: printBlock,
|
RunE: printBlock,
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||||
// TODO: change this to false when we can
|
// TODO: change this to false when we can
|
||||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||||
cmd.Flags().StringSlice(flagSelect, []string{"header", "tx"}, "Fields to return (header|txs|results)")
|
cmd.Flags().StringSlice(flagSelect, []string{"header", "tx"}, "Fields to return (header|txs|results)")
|
||||||
|
|
|
@ -18,7 +18,7 @@ const (
|
||||||
|
|
||||||
// XXX: remove this when not needed
|
// XXX: remove this when not needed
|
||||||
func todoNotImplemented(_ *cobra.Command, _ []string) error {
|
func todoNotImplemented(_ *cobra.Command, _ []string) error {
|
||||||
return errors.New("TODO: Command not yet implemented")
|
return errors.New("todo: Command not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCommands adds a number of rpc-related subcommands
|
// AddCommands adds a number of rpc-related subcommands
|
||||||
|
@ -36,7 +36,7 @@ func initClientCommand() *cobra.Command {
|
||||||
RunE: todoNotImplemented,
|
RunE: todoNotImplemented,
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP(client.FlagChainID, "c", "", "ID of chain we connect to")
|
cmd.Flags().StringP(client.FlagChainID, "c", "", "ID of chain we connect to")
|
||||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||||
cmd.Flags().String(flagGenesis, "", "Genesis file to verify header validity")
|
cmd.Flags().String(flagGenesis, "", "Genesis file to verify header validity")
|
||||||
cmd.Flags().String(flagCommit, "", "File with trusted and signed header")
|
cmd.Flags().String(flagCommit, "", "File with trusted and signed header")
|
||||||
cmd.Flags().String(flagValHash, "", "Hash of trusted validator set (hex-encoded)")
|
cmd.Flags().String(flagValHash, "", "Hash of trusted validator set (hex-encoded)")
|
||||||
|
|
|
@ -18,7 +18,7 @@ func statusCommand() *cobra.Command {
|
||||||
Short: "Query remote node for status",
|
Short: "Query remote node for status",
|
||||||
RunE: printNodeStatus,
|
RunE: printNodeStatus,
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO these next two functions feel kinda hacky based on their placement
|
// TODO these next two functions feel kinda hacky based on their placement
|
||||||
|
@ -22,12 +24,44 @@ func ValidatorCommand() *cobra.Command {
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
RunE: printValidators,
|
RunE: printValidators,
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||||
// TODO: change this to false when we can
|
// TODO: change this to false when we can
|
||||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validator output in bech32 format
|
||||||
|
type ValidatorOutput struct {
|
||||||
|
Address string `json:"address"` // in bech32
|
||||||
|
PubKey string `json:"pub_key"` // in bech32
|
||||||
|
Accum int64 `json:"accum"`
|
||||||
|
VotingPower int64 `json:"voting_power"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validators at a certain height output in bech32 format
|
||||||
|
type ResultValidatorsOutput struct {
|
||||||
|
BlockHeight int64 `json:"block_height"`
|
||||||
|
Validators []ValidatorOutput `json:"validators"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) {
|
||||||
|
bechAddress, err := sdk.Bech32ifyVal(validator.Address)
|
||||||
|
if err != nil {
|
||||||
|
return ValidatorOutput{}, err
|
||||||
|
}
|
||||||
|
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
|
||||||
|
if err != nil {
|
||||||
|
return ValidatorOutput{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValidatorOutput{
|
||||||
|
Address: bechAddress,
|
||||||
|
PubKey: bechValPubkey,
|
||||||
|
Accum: validator.Accum,
|
||||||
|
VotingPower: validator.VotingPower,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
|
func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
|
||||||
// get the node
|
// get the node
|
||||||
node, err := ctx.GetNode()
|
node, err := ctx.GetNode()
|
||||||
|
@ -35,12 +69,23 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := node.Validators(height)
|
validatorsRes, err := node.Validators(height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := cdc.MarshalJSON(res)
|
outputValidatorsRes := ResultValidatorsOutput{
|
||||||
|
BlockHeight: validatorsRes.BlockHeight,
|
||||||
|
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
|
||||||
|
}
|
||||||
|
for i := 0; i < len(validatorsRes.Validators); i++ {
|
||||||
|
outputValidatorsRes.Validators[i], err = bech32ValidatorOutput(validatorsRes.Validators[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := cdc.MarshalJSON(outputValidatorsRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -96,6 +141,7 @@ func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(output)
|
w.Write(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||||
|
|
||||||
// TODO: change this to false when we can
|
// TODO: change this to false when we can
|
||||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||||
|
|
|
@ -19,7 +19,7 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) {
|
||||||
// register REST routes
|
// register REST routes
|
||||||
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
|
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
|
||||||
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, ctx)).Methods("GET")
|
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, ctx)).Methods("GET")
|
||||||
// r.HandleFunc("/txs", SearchTxRequestHandler(cdc)).Methods("GET")
|
r.HandleFunc("/txs", SearchTxRequestHandlerFn(ctx, cdc)).Methods("GET")
|
||||||
// r.HandleFunc("/txs/sign", SignTxRequstHandler).Methods("POST")
|
// r.HandleFunc("/txs/sign", SignTxRequstHandler).Methods("POST")
|
||||||
// r.HandleFunc("/txs/broadcast", BroadcastTxRequestHandler).Methods("POST")
|
// r.HandleFunc("/txs/broadcast", BroadcastTxRequestHandler).Methods("POST")
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,7 +30,11 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
tags := viper.GetStringSlice(flagTags)
|
tags := viper.GetStringSlice(flagTags)
|
||||||
|
|
||||||
output, err := searchTx(context.NewCoreContextFromViper(), cdc, tags)
|
txs, err := searchTxs(context.NewCoreContextFromViper(), cdc, tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
output, err := cdc.MarshalJSON(txs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -38,7 +43,7 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
|
||||||
|
|
||||||
// TODO: change this to false once proofs built in
|
// TODO: change this to false once proofs built in
|
||||||
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
|
||||||
|
@ -47,13 +52,12 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchTx(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]byte, error) {
|
func searchTxs(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]txInfo, error) {
|
||||||
if len(tags) == 0 {
|
if len(tags) == 0 {
|
||||||
return nil, errors.New("Must declare at least one tag to search")
|
return nil, errors.New("must declare at least one tag to search")
|
||||||
}
|
}
|
||||||
// XXX: implement ANY
|
// XXX: implement ANY
|
||||||
query := strings.Join(tags, " AND ")
|
query := strings.Join(tags, " AND ")
|
||||||
|
|
||||||
// get the node
|
// get the node
|
||||||
node, err := ctx.GetNode()
|
node, err := ctx.GetNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -74,11 +78,7 @@ func searchTx(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]byte,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := cdc.MarshalJSON(info)
|
return info, nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return output, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error) {
|
func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error) {
|
||||||
|
@ -102,17 +102,44 @@ func SearchTxRequestHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.Han
|
||||||
tag := r.FormValue("tag")
|
tag := r.FormValue("tag")
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
w.Write([]byte("You need to provide a tag to search for."))
|
w.Write([]byte("You need to provide at least a tag as a key=value pair to search for. Postfix the key with _bech32 to search bech32-encoded addresses or public keys"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
keyValue := strings.Split(tag, "=")
|
||||||
|
key := keyValue[0]
|
||||||
|
value := keyValue[1]
|
||||||
|
if strings.HasSuffix(key, "_bech32") {
|
||||||
|
bech32address := strings.Trim(value, "'")
|
||||||
|
prefix := strings.Split(bech32address, "1")[0]
|
||||||
|
bz, err := sdk.GetFromBech32(bech32address, prefix)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(400)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
tags := []string{tag}
|
tag = strings.TrimRight(key, "_bech32") + "='" + sdk.Address(bz).String() + "'"
|
||||||
output, err := searchTx(ctx, cdc, tags)
|
}
|
||||||
|
|
||||||
|
txs, err := searchTxs(ctx, cdc, []string{tag})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(500)
|
w.WriteHeader(500)
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(txs) == 0 {
|
||||||
|
w.Write([]byte("[]"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := cdc.MarshalJSON(txs)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
w.Write(output)
|
w.Write(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -81,7 +82,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
||||||
app.Router().
|
app.Router().
|
||||||
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
|
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
|
||||||
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
|
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
|
||||||
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
|
AddRoute("stake", stake.NewHandler(app.stakeKeeper)).
|
||||||
|
AddRoute("slashing", slashing.NewHandler(app.slashingKeeper))
|
||||||
|
|
||||||
// initialize BaseApp
|
// initialize BaseApp
|
||||||
app.SetInitChainer(app.initChainer)
|
app.SetInitChainer(app.initChainer)
|
||||||
|
@ -143,6 +145,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
||||||
// load the accounts
|
// load the accounts
|
||||||
for _, gacc := range genesisState.Accounts {
|
for _, gacc := range genesisState.Accounts {
|
||||||
acc := gacc.ToAccount()
|
acc := gacc.ToAccount()
|
||||||
|
acc.AccountNumber = app.accountMapper.GetNextAccountNumber(ctx)
|
||||||
app.accountMapper.SetAccount(ctx, acc)
|
app.accountMapper.SetAccount(ctx, acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +156,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
||||||
}
|
}
|
||||||
|
|
||||||
// export the state of gaia for a genesis file
|
// export the state of gaia for a genesis file
|
||||||
func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||||
ctx := app.NewContext(true, abci.Header{})
|
ctx := app.NewContext(true, abci.Header{})
|
||||||
|
|
||||||
// iterate to get the accounts
|
// iterate to get the accounts
|
||||||
|
@ -169,5 +172,10 @@ func (app *GaiaApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
||||||
Accounts: accounts,
|
Accounts: accounts,
|
||||||
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
|
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
|
||||||
}
|
}
|
||||||
return wire.MarshalJSONIndent(app.cdc, genState)
|
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
validators = stake.WriteValidators(ctx, app.stakeKeeper)
|
||||||
|
return appState, validators, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,101 +1,13 @@
|
||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
|
||||||
"github.com/tendermint/tmlibs/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Construct some global addrs and txs for tests.
|
|
||||||
var (
|
|
||||||
chainID = "" // TODO
|
|
||||||
|
|
||||||
accName = "foobart"
|
|
||||||
|
|
||||||
priv1 = crypto.GenPrivKeyEd25519()
|
|
||||||
addr1 = priv1.PubKey().Address()
|
|
||||||
priv2 = crypto.GenPrivKeyEd25519()
|
|
||||||
addr2 = priv2.PubKey().Address()
|
|
||||||
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
|
||||||
priv4 = crypto.GenPrivKeyEd25519()
|
|
||||||
addr4 = priv4.PubKey().Address()
|
|
||||||
coins = sdk.Coins{{"foocoin", 10}}
|
|
||||||
halfCoins = sdk.Coins{{"foocoin", 5}}
|
|
||||||
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
|
|
||||||
fee = auth.StdFee{
|
|
||||||
sdk.Coins{{"foocoin", 0}},
|
|
||||||
100000,
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg1 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
|
||||||
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg2 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
bank.NewOutput(addr2, halfCoins),
|
|
||||||
bank.NewOutput(addr3, halfCoins),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg3 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{
|
|
||||||
bank.NewInput(addr1, coins),
|
|
||||||
bank.NewInput(addr4, coins),
|
|
||||||
},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
bank.NewOutput(addr2, coins),
|
|
||||||
bank.NewOutput(addr3, coins),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg4 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{
|
|
||||||
bank.NewInput(addr2, coins),
|
|
||||||
},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
bank.NewOutput(addr1, coins),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg5 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{
|
|
||||||
bank.NewInput(addr1, manyCoins),
|
|
||||||
},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
bank.NewOutput(addr2, manyCoins),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func loggerAndDB() (log.Logger, dbm.DB) {
|
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
|
||||||
db := dbm.NewMemDB()
|
|
||||||
return logger, db
|
|
||||||
}
|
|
||||||
|
|
||||||
func newGaiaApp() *GaiaApp {
|
|
||||||
logger, db := loggerAndDB()
|
|
||||||
return NewGaiaApp(logger, db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
||||||
genaccs := make([]GenesisAccount, len(accs))
|
genaccs := make([]GenesisAccount, len(accs))
|
||||||
for i, acc := range accs {
|
for i, acc := range accs {
|
||||||
|
@ -119,382 +31,3 @@ func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//_______________________________________________________________________
|
|
||||||
|
|
||||||
func TestMsgs(t *testing.T) {
|
|
||||||
gapp := newGaiaApp()
|
|
||||||
require.Nil(t, setGenesis(gapp))
|
|
||||||
|
|
||||||
msgs := []struct {
|
|
||||||
msg sdk.Msg
|
|
||||||
}{
|
|
||||||
{sendMsg1},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, m := range msgs {
|
|
||||||
// Run a CheckDeliver
|
|
||||||
SignCheckDeliver(t, gapp, m.msg, []int64{int64(i)}, false, priv1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenesis(t *testing.T) {
|
|
||||||
logger, dbs := loggerAndDB()
|
|
||||||
gapp := NewGaiaApp(logger, dbs)
|
|
||||||
|
|
||||||
// Construct some genesis bytes to reflect GaiaAccount
|
|
||||||
pk := crypto.GenPrivKeyEd25519().PubKey()
|
|
||||||
addr := pk.Address()
|
|
||||||
coins, err := sdk.ParseCoins("77foocoin,99barcoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
baseAcc := &auth.BaseAccount{
|
|
||||||
Address: addr,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setGenesis(gapp, baseAcc)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// A checkTx context
|
|
||||||
ctx := gapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := gapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
|
||||||
assert.Equal(t, baseAcc, res1)
|
|
||||||
|
|
||||||
// reload app and ensure the account is still there
|
|
||||||
gapp = NewGaiaApp(logger, dbs)
|
|
||||||
ctx = gapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 = gapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
|
||||||
assert.Equal(t, baseAcc, res1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgSendWithAccounts(t *testing.T) {
|
|
||||||
gapp := newGaiaApp()
|
|
||||||
|
|
||||||
// Construct some genesis bytes to reflect GaiaAccount
|
|
||||||
// Give 77 foocoin to the first key
|
|
||||||
coins, err := sdk.ParseCoins("77foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
baseAcc := &auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
err = setGenesis(gapp, baseAcc)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, baseAcc, res1.(*auth.BaseAccount))
|
|
||||||
|
|
||||||
// Run a CheckDeliver
|
|
||||||
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, true, priv1)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, gapp, addr1, "67foocoin")
|
|
||||||
CheckBalance(t, gapp, addr2, "10foocoin")
|
|
||||||
|
|
||||||
// Delivering again should cause replay error
|
|
||||||
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, false, priv1)
|
|
||||||
|
|
||||||
// bumping the txnonce number without resigning should be an auth error
|
|
||||||
tx := genTx(sendMsg1, []int64{0}, priv1)
|
|
||||||
tx.Signatures[0].Sequence = 1
|
|
||||||
res := gapp.Deliver(tx)
|
|
||||||
|
|
||||||
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
|
|
||||||
|
|
||||||
// resigning the tx with the bumped sequence should work
|
|
||||||
SignCheckDeliver(t, gapp, sendMsg1, []int64{1}, true, priv1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgSendMultipleOut(t *testing.T) {
|
|
||||||
gapp := newGaiaApp()
|
|
||||||
|
|
||||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
acc1 := &auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
acc2 := &auth.BaseAccount{
|
|
||||||
Address: addr2,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setGenesis(gapp, acc1, acc2)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
SignCheckDeliver(t, gapp, sendMsg2, []int64{0}, true, priv1)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, gapp, addr1, "32foocoin")
|
|
||||||
CheckBalance(t, gapp, addr2, "47foocoin")
|
|
||||||
CheckBalance(t, gapp, addr3, "5foocoin")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSengMsgMultipleInOut(t *testing.T) {
|
|
||||||
gapp := newGaiaApp()
|
|
||||||
|
|
||||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
acc1 := &auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
acc2 := &auth.BaseAccount{
|
|
||||||
Address: addr2,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
acc4 := &auth.BaseAccount{
|
|
||||||
Address: addr4,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setGenesis(gapp, acc1, acc2, acc4)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
// CheckDeliver
|
|
||||||
SignCheckDeliver(t, gapp, sendMsg3, []int64{0, 0}, true, priv1, priv4)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, gapp, addr1, "32foocoin")
|
|
||||||
CheckBalance(t, gapp, addr4, "32foocoin")
|
|
||||||
CheckBalance(t, gapp, addr2, "52foocoin")
|
|
||||||
CheckBalance(t, gapp, addr3, "10foocoin")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgSendDependent(t *testing.T) {
|
|
||||||
gapp := newGaiaApp()
|
|
||||||
|
|
||||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
acc1 := &auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setGenesis(gapp, acc1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// CheckDeliver
|
|
||||||
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, true, priv1)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, gapp, addr1, "32foocoin")
|
|
||||||
CheckBalance(t, gapp, addr2, "10foocoin")
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
SignCheckDeliver(t, gapp, sendMsg4, []int64{0}, true, priv2)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, gapp, addr1, "42foocoin")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIBCMsgs(t *testing.T) {
|
|
||||||
gapp := newGaiaApp()
|
|
||||||
|
|
||||||
sourceChain := "source-chain"
|
|
||||||
destChain := "dest-chain"
|
|
||||||
|
|
||||||
baseAcc := &auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := setGenesis(gapp, baseAcc)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, baseAcc, res1)
|
|
||||||
|
|
||||||
packet := ibc.IBCPacket{
|
|
||||||
SrcAddr: addr1,
|
|
||||||
DestAddr: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
SrcChain: sourceChain,
|
|
||||||
DestChain: destChain,
|
|
||||||
}
|
|
||||||
|
|
||||||
transferMsg := ibc.IBCTransferMsg{
|
|
||||||
IBCPacket: packet,
|
|
||||||
}
|
|
||||||
|
|
||||||
receiveMsg := ibc.IBCReceiveMsg{
|
|
||||||
IBCPacket: packet,
|
|
||||||
Relayer: addr1,
|
|
||||||
Sequence: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
SignCheckDeliver(t, gapp, transferMsg, []int64{0}, true, priv1)
|
|
||||||
CheckBalance(t, gapp, addr1, "")
|
|
||||||
SignCheckDeliver(t, gapp, transferMsg, []int64{1}, false, priv1)
|
|
||||||
SignCheckDeliver(t, gapp, receiveMsg, []int64{2}, true, priv1)
|
|
||||||
CheckBalance(t, gapp, addr1, "10foocoin")
|
|
||||||
SignCheckDeliver(t, gapp, receiveMsg, []int64{3}, false, priv1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStakeMsgs(t *testing.T) {
|
|
||||||
gapp := newGaiaApp()
|
|
||||||
|
|
||||||
genCoins, err := sdk.ParseCoins("42steak")
|
|
||||||
require.Nil(t, err)
|
|
||||||
bondCoin, err := sdk.ParseCoin("10steak")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
acc1 := &auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
acc2 := &auth.BaseAccount{
|
|
||||||
Address: addr2,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setGenesis(gapp, acc1, acc2)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
res2 := gapp.accountMapper.GetAccount(ctxCheck, addr2)
|
|
||||||
require.Equal(t, acc1, res1)
|
|
||||||
require.Equal(t, acc2, res2)
|
|
||||||
|
|
||||||
// Create Validator
|
|
||||||
|
|
||||||
description := stake.NewDescription("foo_moniker", "", "", "")
|
|
||||||
createValidatorMsg := stake.NewMsgCreateValidator(
|
|
||||||
addr1, priv1.PubKey(), bondCoin, description,
|
|
||||||
)
|
|
||||||
SignCheckDeliver(t, gapp, createValidatorMsg, []int64{0}, true, priv1)
|
|
||||||
|
|
||||||
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
|
|
||||||
res1 = gapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
|
||||||
require.Equal(t, genCoins.Minus(sdk.Coins{bondCoin}), res1.GetCoins())
|
|
||||||
validator, found := gapp.stakeKeeper.GetValidator(ctxDeliver, addr1)
|
|
||||||
require.True(t, found)
|
|
||||||
require.Equal(t, addr1, validator.Owner)
|
|
||||||
require.Equal(t, sdk.Bonded, validator.Status())
|
|
||||||
require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded()))
|
|
||||||
|
|
||||||
// check the bond that should have been created as well
|
|
||||||
bond, found := gapp.stakeKeeper.GetDelegation(ctxDeliver, addr1, addr1)
|
|
||||||
require.True(sdk.RatEq(t, sdk.NewRat(10), bond.Shares))
|
|
||||||
|
|
||||||
// Edit Validator
|
|
||||||
|
|
||||||
description = stake.NewDescription("bar_moniker", "", "", "")
|
|
||||||
editValidatorMsg := stake.NewMsgEditValidator(
|
|
||||||
addr1, description,
|
|
||||||
)
|
|
||||||
SignDeliver(t, gapp, editValidatorMsg, []int64{1}, true, priv1)
|
|
||||||
|
|
||||||
validator, found = gapp.stakeKeeper.GetValidator(ctxDeliver, addr1)
|
|
||||||
require.True(t, found)
|
|
||||||
require.Equal(t, description, validator.Description)
|
|
||||||
|
|
||||||
// Delegate
|
|
||||||
|
|
||||||
delegateMsg := stake.NewMsgDelegate(
|
|
||||||
addr2, addr1, bondCoin,
|
|
||||||
)
|
|
||||||
SignDeliver(t, gapp, delegateMsg, []int64{0}, true, priv2)
|
|
||||||
|
|
||||||
res2 = gapp.accountMapper.GetAccount(ctxDeliver, addr2)
|
|
||||||
require.Equal(t, genCoins.Minus(sdk.Coins{bondCoin}), res2.GetCoins())
|
|
||||||
bond, found = gapp.stakeKeeper.GetDelegation(ctxDeliver, addr2, addr1)
|
|
||||||
require.True(t, found)
|
|
||||||
require.Equal(t, addr2, bond.DelegatorAddr)
|
|
||||||
require.Equal(t, addr1, bond.ValidatorAddr)
|
|
||||||
require.True(sdk.RatEq(t, sdk.NewRat(10), bond.Shares))
|
|
||||||
|
|
||||||
// Unbond
|
|
||||||
|
|
||||||
unbondMsg := stake.NewMsgUnbond(
|
|
||||||
addr2, addr1, "MAX",
|
|
||||||
)
|
|
||||||
SignDeliver(t, gapp, unbondMsg, []int64{1}, true, priv2)
|
|
||||||
|
|
||||||
res2 = gapp.accountMapper.GetAccount(ctxDeliver, addr2)
|
|
||||||
require.Equal(t, genCoins, res2.GetCoins())
|
|
||||||
_, found = gapp.stakeKeeper.GetDelegation(ctxDeliver, addr2, addr1)
|
|
||||||
require.False(t, found)
|
|
||||||
}
|
|
||||||
|
|
||||||
//____________________________________________________________________________________
|
|
||||||
|
|
||||||
func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) {
|
|
||||||
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
|
|
||||||
res2 := gapp.accountMapper.GetAccount(ctxDeliver, addr)
|
|
||||||
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) auth.StdTx {
|
|
||||||
sigs := make([]auth.StdSignature, len(priv))
|
|
||||||
for i, p := range priv {
|
|
||||||
sigs[i] = auth.StdSignature{
|
|
||||||
PubKey: p.PubKey(),
|
|
||||||
Signature: p.Sign(auth.StdSignBytes(chainID, seq, fee, msg)),
|
|
||||||
Sequence: seq[i],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return auth.NewStdTx(msg, fee, sigs)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func SignCheckDeliver(t *testing.T, gapp *GaiaApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
|
|
||||||
|
|
||||||
// Sign the tx
|
|
||||||
tx := genTx(msg, seq, priv...)
|
|
||||||
|
|
||||||
// Run a Check
|
|
||||||
res := gapp.Check(tx)
|
|
||||||
if expPass {
|
|
||||||
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
} else {
|
|
||||||
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
gapp.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
res = gapp.Deliver(tx)
|
|
||||||
if expPass {
|
|
||||||
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
} else {
|
|
||||||
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
}
|
|
||||||
gapp.EndBlock(abci.RequestEndBlock{})
|
|
||||||
|
|
||||||
// XXX fix code or add explaination as to why using commit breaks a bunch of these tests
|
|
||||||
//gapp.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX the only reason we are using Sign Deliver here is because the tests
|
|
||||||
// break on check tx the second time you use SignCheckDeliver in a test because
|
|
||||||
// the checktx state has not been updated likely because commit is not being
|
|
||||||
// called!
|
|
||||||
func SignDeliver(t *testing.T, gapp *GaiaApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
|
|
||||||
|
|
||||||
// Sign the tx
|
|
||||||
tx := genTx(msg, seq, priv...)
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
gapp.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
res := gapp.Deliver(tx)
|
|
||||||
if expPass {
|
|
||||||
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
} else {
|
|
||||||
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
}
|
|
||||||
gapp.EndBlock(abci.RequestEndBlock{})
|
|
||||||
}
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
||||||
overwrite := viper.GetBool(flagOWK)
|
overwrite := viper.GetBool(flagOWK)
|
||||||
name := viper.GetString(flagName)
|
name := viper.GetString(flagName)
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return nil, nil, tmtypes.GenesisValidator{}, errors.New("Must specify --name (validator moniker)")
|
return nil, nil, tmtypes.GenesisValidator{}, errors.New("must specify --name (validator moniker)")
|
||||||
}
|
}
|
||||||
|
|
||||||
var addr sdk.Address
|
var addr sdk.Address
|
||||||
|
@ -108,7 +108,8 @@ func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cliPrint = json.RawMessage(bz)
|
cliPrint = json.RawMessage(bz)
|
||||||
return GaiaAppGenTxNF(cdc, pk, addr, name, overwrite)
|
appGenTx,_,validator,err = GaiaAppGenTxNF(cdc, pk, addr, name, overwrite)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a gaia genesis transaction without flags
|
// Generate a gaia genesis transaction without flags
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -50,7 +49,7 @@ func TestGaiaCLISend(t *testing.T) {
|
||||||
assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak"))
|
||||||
|
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), 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
|
tests.WaitForNextHeightTM(port)
|
||||||
|
|
||||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
|
||||||
|
@ -59,7 +58,7 @@ func TestGaiaCLISend(t *testing.T) {
|
||||||
|
|
||||||
// test autosequencing
|
// test autosequencing
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), 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
|
tests.WaitForNextHeightTM(port)
|
||||||
|
|
||||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
assert.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak"))
|
||||||
|
@ -96,7 +95,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), 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
|
tests.WaitForNextHeightTM(port)
|
||||||
|
|
||||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
|
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak"))
|
||||||
|
@ -112,7 +111,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
||||||
|
|
||||||
executeWrite(t, cvStr, pass)
|
executeWrite(t, cvStr, pass)
|
||||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
tests.WaitForNextHeightTM(port)
|
||||||
|
|
||||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
|
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
|
||||||
|
@ -131,7 +130,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr))
|
t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr))
|
||||||
|
|
||||||
executeWrite(t, unbondStr, pass)
|
executeWrite(t, unbondStr, pass)
|
||||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
tests.WaitForNextHeightTM(port)
|
||||||
|
|
||||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||||
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
|
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak"), "%v", barAcc)
|
||||||
|
@ -150,6 +149,8 @@ func executeWrite(t *testing.T, cmdStr string, writes ...string) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
proc.Wait()
|
proc.Wait()
|
||||||
|
// bz := proc.StdoutBuffer.Bytes()
|
||||||
|
// fmt.Println("EXEC WRITE", string(bz))
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeInit(t *testing.T, cmdStr string) (chainID string) {
|
func executeInit(t *testing.T, cmdStr string) (chainID string) {
|
||||||
|
@ -170,7 +171,13 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.Address, crypto.PubKey)
|
||||||
var ko keys.KeyOutput
|
var ko keys.KeyOutput
|
||||||
keys.UnmarshalJSON([]byte(out), &ko)
|
keys.UnmarshalJSON([]byte(out), &ko)
|
||||||
|
|
||||||
return ko.Address, ko.PubKey
|
address, err := sdk.GetAccAddressBech32(ko.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
pk, err := sdk.GetAccPubKeyBech32(ko.PubKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return address, pk
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -26,7 +27,7 @@ func main() {
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
|
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
|
||||||
server.ConstructAppCreator(newApp, "gaia"),
|
server.ConstructAppCreator(newApp, "gaia"),
|
||||||
server.ConstructAppExporter(exportAppState, "gaia"))
|
server.ConstructAppExporter(exportAppStateAndTMValidators, "gaia"))
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
||||||
|
@ -37,7 +38,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
||||||
return app.NewGaiaApp(logger, db)
|
return app.NewGaiaApp(logger, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
|
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
gapp := app.NewGaiaApp(logger, db)
|
gapp := app.NewGaiaApp(logger, db)
|
||||||
return gapp.ExportAppStateJSON()
|
return gapp.ExportAppStateAndValidators()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Gaiadebug
|
||||||
|
|
||||||
|
Simple tool for simple debugging.
|
||||||
|
|
||||||
|
We try to accept both hex and base64 formats and provide a useful response.
|
||||||
|
|
||||||
|
Note we often encode bytes as hex in the logs, but as base64 in the JSON.
|
||||||
|
|
||||||
|
## Pubkeys
|
||||||
|
|
||||||
|
The following give the same result:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiadebug pubkey TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4=
|
||||||
|
gaiadebug pubkey 4D94D09DFA8EB22F3D49EA17567230FAD9C5267AF85FCA950B453C02C126164E
|
||||||
|
```
|
||||||
|
|
||||||
|
## Txs
|
||||||
|
|
||||||
|
Pass in a hex/base64 tx and get back the full JSON
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiadebug tx <hex or base64 transaction>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hack
|
||||||
|
|
||||||
|
This is a command with boilerplate for using Go as a scripting language to hack
|
||||||
|
on an existing Gaia state.
|
||||||
|
|
||||||
|
Currently we have an example for the state of gaia-6001 after it
|
||||||
|
[crashed](https://github.com/cosmos/cosmos-sdk/blob/master/cmd/gaia/testnets/STATUS.md#june-13-2018-230-est---published-postmortem-of-gaia-6001-failure).
|
||||||
|
If you run `gaiadebug hack $HOME/.gaiad` on that
|
||||||
|
state, it will do a binary search on the state history to find when the state
|
||||||
|
invariant was violated.
|
|
@ -0,0 +1,243 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
|
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/ibc"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
|
||||||
|
gaia "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runHackCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
|
if len(args) != 1 {
|
||||||
|
return fmt.Errorf("Expected 1 arg")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ".gaiad"
|
||||||
|
dataDir := args[0]
|
||||||
|
dataDir = path.Join(dataDir, "data")
|
||||||
|
|
||||||
|
// load the app
|
||||||
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||||
|
db, err := dbm.NewGoLevelDB("gaia", dataDir)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
app := NewGaiaApp(logger, db)
|
||||||
|
|
||||||
|
// print some info
|
||||||
|
id := app.LastCommitID()
|
||||||
|
lastBlockHeight := app.LastBlockHeight()
|
||||||
|
fmt.Println("ID", id)
|
||||||
|
fmt.Println("LastBlockHeight", lastBlockHeight)
|
||||||
|
|
||||||
|
//----------------------------------------------------
|
||||||
|
// XXX: start hacking!
|
||||||
|
//----------------------------------------------------
|
||||||
|
// eg. gaia-6001 testnet bug
|
||||||
|
// We paniced when iterating through the "bypower" keys.
|
||||||
|
// The following powerKey was there, but the corresponding "trouble" validator did not exist.
|
||||||
|
// So here we do a binary search on the past states to find when the powerKey first showed up ...
|
||||||
|
|
||||||
|
// owner of the validator the bonds, gets revoked, later unbonds, and then later is still found in the bypower store
|
||||||
|
trouble := hexToBytes("D3DC0FF59F7C3B548B7AFA365561B87FD0208AF8")
|
||||||
|
// this is his "bypower" key
|
||||||
|
powerKey := hexToBytes("05303030303030303030303033FFFFFFFFFFFF4C0C0000FFFED3DC0FF59F7C3B548B7AFA365561B87FD0208AF8")
|
||||||
|
|
||||||
|
topHeight := lastBlockHeight
|
||||||
|
bottomHeight := int64(0)
|
||||||
|
checkHeight := topHeight
|
||||||
|
for {
|
||||||
|
// load the given version of the state
|
||||||
|
err = app.LoadVersion(checkHeight, app.keyMain)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
ctx := app.NewContext(true, abci.Header{})
|
||||||
|
|
||||||
|
// check for the powerkey and the validator from the store
|
||||||
|
store := ctx.KVStore(app.keyStake)
|
||||||
|
res := store.Get(powerKey)
|
||||||
|
val, _ := app.stakeKeeper.GetValidator(ctx, trouble)
|
||||||
|
fmt.Println("checking height", checkHeight, res, val)
|
||||||
|
if res == nil {
|
||||||
|
bottomHeight = checkHeight
|
||||||
|
} else {
|
||||||
|
topHeight = checkHeight
|
||||||
|
}
|
||||||
|
checkHeight = (topHeight + bottomHeight) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func base64ToPub(b64 string) crypto.PubKeyEd25519 {
|
||||||
|
data, _ := base64.StdEncoding.DecodeString(b64)
|
||||||
|
var pubKey crypto.PubKeyEd25519
|
||||||
|
copy(pubKey[:], data)
|
||||||
|
return pubKey
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexToBytes(h string) []byte {
|
||||||
|
trouble, _ := hex.DecodeString(h)
|
||||||
|
return trouble
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// NOTE: This is all copied from gaia/app/app.go
|
||||||
|
// so we can access internal fields!
|
||||||
|
|
||||||
|
const (
|
||||||
|
appName = "GaiaApp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// default home directories for expected binaries
|
||||||
|
var (
|
||||||
|
DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli")
|
||||||
|
DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extended ABCI application
|
||||||
|
type GaiaApp struct {
|
||||||
|
*bam.BaseApp
|
||||||
|
cdc *wire.Codec
|
||||||
|
|
||||||
|
// keys to access the substores
|
||||||
|
keyMain *sdk.KVStoreKey
|
||||||
|
keyAccount *sdk.KVStoreKey
|
||||||
|
keyIBC *sdk.KVStoreKey
|
||||||
|
keyStake *sdk.KVStoreKey
|
||||||
|
keySlashing *sdk.KVStoreKey
|
||||||
|
|
||||||
|
// Manage getting and setting accounts
|
||||||
|
accountMapper auth.AccountMapper
|
||||||
|
feeCollectionKeeper auth.FeeCollectionKeeper
|
||||||
|
coinKeeper bank.Keeper
|
||||||
|
ibcMapper ibc.Mapper
|
||||||
|
stakeKeeper stake.Keeper
|
||||||
|
slashingKeeper slashing.Keeper
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
|
||||||
|
cdc := MakeCodec()
|
||||||
|
|
||||||
|
// create your application object
|
||||||
|
var app = &GaiaApp{
|
||||||
|
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
|
||||||
|
cdc: cdc,
|
||||||
|
keyMain: sdk.NewKVStoreKey("main"),
|
||||||
|
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||||
|
keyIBC: sdk.NewKVStoreKey("ibc"),
|
||||||
|
keyStake: sdk.NewKVStoreKey("stake"),
|
||||||
|
keySlashing: sdk.NewKVStoreKey("slashing"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the accountMapper
|
||||||
|
app.accountMapper = auth.NewAccountMapper(
|
||||||
|
app.cdc,
|
||||||
|
app.keyAccount, // target store
|
||||||
|
&auth.BaseAccount{}, // prototype
|
||||||
|
)
|
||||||
|
|
||||||
|
// add handlers
|
||||||
|
app.coinKeeper = bank.NewKeeper(app.accountMapper)
|
||||||
|
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
|
||||||
|
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
|
||||||
|
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace))
|
||||||
|
|
||||||
|
// register message routes
|
||||||
|
app.Router().
|
||||||
|
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
|
||||||
|
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
|
||||||
|
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
|
||||||
|
|
||||||
|
// initialize BaseApp
|
||||||
|
app.SetInitChainer(app.initChainer)
|
||||||
|
app.SetBeginBlocker(app.BeginBlocker)
|
||||||
|
app.SetEndBlocker(app.EndBlocker)
|
||||||
|
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
||||||
|
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing)
|
||||||
|
err := app.LoadLatestVersion(app.keyMain)
|
||||||
|
if err != nil {
|
||||||
|
cmn.Exit(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom tx codec
|
||||||
|
func MakeCodec() *wire.Codec {
|
||||||
|
var cdc = wire.NewCodec()
|
||||||
|
ibc.RegisterWire(cdc)
|
||||||
|
bank.RegisterWire(cdc)
|
||||||
|
stake.RegisterWire(cdc)
|
||||||
|
slashing.RegisterWire(cdc)
|
||||||
|
auth.RegisterWire(cdc)
|
||||||
|
sdk.RegisterWire(cdc)
|
||||||
|
wire.RegisterCrypto(cdc)
|
||||||
|
return cdc
|
||||||
|
}
|
||||||
|
|
||||||
|
// application updates every end block
|
||||||
|
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||||
|
tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper)
|
||||||
|
|
||||||
|
return abci.ResponseBeginBlock{
|
||||||
|
Tags: tags.ToKVPairs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// application updates every end block
|
||||||
|
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||||
|
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
|
||||||
|
|
||||||
|
return abci.ResponseEndBlock{
|
||||||
|
ValidatorUpdates: validatorUpdates,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom logic for gaia initialization
|
||||||
|
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||||
|
stateJSON := req.AppStateBytes
|
||||||
|
// TODO is this now the whole genesis file?
|
||||||
|
|
||||||
|
var genesisState gaia.GenesisState
|
||||||
|
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
|
||||||
|
if err != nil {
|
||||||
|
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||||
|
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the accounts
|
||||||
|
for _, gacc := range genesisState.Accounts {
|
||||||
|
acc := gacc.ToAccount()
|
||||||
|
app.accountMapper.SetAccount(ctx, acc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the initial stake information
|
||||||
|
stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
|
||||||
|
return abci.ResponseInitChain{}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
gaia "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(txCmd)
|
||||||
|
rootCmd.AddCommand(pubkeyCmd)
|
||||||
|
rootCmd.AddCommand(hackCmd)
|
||||||
|
rootCmd.AddCommand(rawBytesCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "gaiadebug",
|
||||||
|
Short: "Gaia debug tool",
|
||||||
|
SilenceUsage: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
var txCmd = &cobra.Command{
|
||||||
|
Use: "tx",
|
||||||
|
Short: "Decode a gaia tx from hex or base64",
|
||||||
|
RunE: runTxCmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
var pubkeyCmd = &cobra.Command{
|
||||||
|
Use: "pubkey",
|
||||||
|
Short: "Decode a pubkey from hex or base64",
|
||||||
|
RunE: runPubKeyCmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
var hackCmd = &cobra.Command{
|
||||||
|
Use: "hack",
|
||||||
|
Short: "Boilerplate to Hack on an existing state by scripting some Go...",
|
||||||
|
RunE: runHackCmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
var rawBytesCmd = &cobra.Command{
|
||||||
|
Use: "raw-bytes",
|
||||||
|
Short: "Convert raw bytes output (eg. [10 21 13 255]) to hex",
|
||||||
|
RunE: runRawBytesCmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
func runRawBytesCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return fmt.Errorf("Expected single arg")
|
||||||
|
}
|
||||||
|
stringBytes := args[0]
|
||||||
|
stringBytes = strings.Trim(stringBytes, "[")
|
||||||
|
stringBytes = strings.Trim(stringBytes, "]")
|
||||||
|
spl := strings.Split(stringBytes, " ")
|
||||||
|
|
||||||
|
byteArray := []byte{}
|
||||||
|
for _, s := range spl {
|
||||||
|
b, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
byteArray = append(byteArray, byte(b))
|
||||||
|
}
|
||||||
|
fmt.Printf("%X\n", byteArray)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runPubKeyCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return fmt.Errorf("Expected single arg")
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkeyString := args[0]
|
||||||
|
|
||||||
|
// try hex, then base64
|
||||||
|
pubkeyBytes, err := hex.DecodeString(pubkeyString)
|
||||||
|
if err != nil {
|
||||||
|
var err2 error
|
||||||
|
pubkeyBytes, err2 = base64.StdEncoding.DecodeString(pubkeyString)
|
||||||
|
if err2 != nil {
|
||||||
|
return fmt.Errorf(`Expected hex or base64. Got errors:
|
||||||
|
hex: %v,
|
||||||
|
base64: %v
|
||||||
|
`, err, err2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cdc := gaia.MakeCodec()
|
||||||
|
var pubKey crypto.PubKeyEd25519
|
||||||
|
copy(pubKey[:], pubkeyBytes)
|
||||||
|
pubKeyJSONBytes, err := cdc.MarshalJSON(pubKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println("Address:", pubKey.Address())
|
||||||
|
fmt.Printf("Hex: %X\n", pubkeyBytes)
|
||||||
|
fmt.Println("JSON (base64):", string(pubKeyJSONBytes))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTxCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) != 1 {
|
||||||
|
return fmt.Errorf("Expected single arg")
|
||||||
|
}
|
||||||
|
|
||||||
|
txString := args[0]
|
||||||
|
|
||||||
|
// try hex, then base64
|
||||||
|
txBytes, err := hex.DecodeString(txString)
|
||||||
|
if err != nil {
|
||||||
|
var err2 error
|
||||||
|
txBytes, err2 = base64.StdEncoding.DecodeString(txString)
|
||||||
|
if err2 != nil {
|
||||||
|
return fmt.Errorf(`Expected hex or base64. Got errors:
|
||||||
|
hex: %v,
|
||||||
|
base64: %v
|
||||||
|
`, err, err2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tx = auth.StdTx{}
|
||||||
|
cdc := gaia.MakeCodec()
|
||||||
|
|
||||||
|
err = cdc.UnmarshalBinary(txBytes, &tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bz, err := cdc.MarshalJSON(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
err = json.Indent(buf, bz, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(buf.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := rootCmd.Execute()
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
|
@ -0,0 +1,258 @@
|
||||||
|
# Connect to the `gaia-6002` Testnet
|
||||||
|
|
||||||
|
Note: We are aware this documentation is sub-par. We are working to
|
||||||
|
improve the tooling and the documentation to make this process as painless as
|
||||||
|
possible. In the meantime, join the
|
||||||
|
[Validator Chat](https://riot.im/app/#/room/#cosmos_validators:matrix.org)
|
||||||
|
for technical support. Thanks very much for your patience. :)
|
||||||
|
|
||||||
|
## Setting Up a New Node
|
||||||
|
|
||||||
|
These instructions are for setting up a brand new full node from scratch. If you ran a full node on a previous testnet, please skip to [Upgrading From Previous Testnet](#upgrading-from-previous-testnet).
|
||||||
|
|
||||||
|
### Install Go
|
||||||
|
|
||||||
|
Install `go` by following the [official docs](https://golang.org/doc/install).
|
||||||
|
**Go 1.10+** is required for the Cosmos SDK.
|
||||||
|
|
||||||
|
### Install Cosmos SDK
|
||||||
|
|
||||||
|
Next, let's install the testnet's version of the Cosmos SDK.
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir -p $GOPATH/src/github.com/cosmos
|
||||||
|
cd $GOPATH/src/github.com/cosmos
|
||||||
|
git clone https://github.com/cosmos/cosmos-sdk
|
||||||
|
cd cosmos-sdk && git checkout v0.19.0
|
||||||
|
make get_tools && make get_vendor_deps && make install
|
||||||
|
```
|
||||||
|
|
||||||
|
That will install the `gaiad` and `gaiacli` binaries. Verify that everything is OK:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiad version
|
||||||
|
0.19.0-<commit>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node Setup
|
||||||
|
|
||||||
|
Create the required configuration files:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiad init
|
||||||
|
```
|
||||||
|
|
||||||
|
Name your node by editing the `moniker` in `$HOME/.gaiad/config/config.toml`. Note that only ASCII characters are supported. Using Unicode renders your node unconnectable.
|
||||||
|
|
||||||
|
```
|
||||||
|
# A custom human readable name for this node
|
||||||
|
moniker = "<your_custom_name>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Your full node has been initialized! Please skip to [Genesis & Seeds](#genesis--seeds).
|
||||||
|
|
||||||
|
## Upgrading From Previous Testnet
|
||||||
|
|
||||||
|
These instructions are for full nodes that have ran on previous testnets and would like to upgrade to the latest testnet.
|
||||||
|
|
||||||
|
### Reset Data
|
||||||
|
|
||||||
|
First, remove the outdated files and reset the data.
|
||||||
|
|
||||||
|
```
|
||||||
|
rm $HOME/.gaiad/config/addrbook.json $HOME/.gaiad/config/genesis.json
|
||||||
|
gaiad unsafe_reset_all
|
||||||
|
```
|
||||||
|
|
||||||
|
Your node is now in a pristine state while keeping the original `priv_validator.json` and `config.toml`. If you had any sentry nodes or full nodes setup before,
|
||||||
|
your node will still try to connect to them, but may fail if they haven't also
|
||||||
|
been upgraded.
|
||||||
|
|
||||||
|
**WARNING:** Make sure that every node has a unique `priv_validator.json`. Do not copy the `priv_validator.json` from an old node to multiple new nodes. Running two nodes with the same `priv_validator.json` will cause you to double sign.
|
||||||
|
|
||||||
|
### Software Upgrade
|
||||||
|
|
||||||
|
Now it is time to upgrade the software:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd $GOPATH/src/github.com/cosmos/cosmos-sdk
|
||||||
|
git fetch --all && git checkout v0.19.0
|
||||||
|
make update_tools && make get_vendor_deps && make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Your full node has been cleanly upgraded!
|
||||||
|
|
||||||
|
## Genesis & Seeds
|
||||||
|
|
||||||
|
### Copy the Genesis File
|
||||||
|
|
||||||
|
Copy the testnet's `genesis.json` file and place it in `gaiad`'s config directory.
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir -p $HOME/.gaiad/config
|
||||||
|
cp -a $GOPATH/src/github.com/cosmos/cosmos-sdk/cmd/gaia/testnets/gaia-6002/genesis.json $HOME/.gaiad/config/genesis.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Seed Nodes
|
||||||
|
|
||||||
|
Your node needs to know how to find peers. You'll need to add healthy seed nodes to `$HOME/.gaiad/config/config.toml`. Here are some seed nodes you can use:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Comma separated list of seed nodes to connect to
|
||||||
|
seeds = "38aa9bec3998f12ae9088b21a2d910d19d565c27@gaia-6002.coinculture.net:46656,80a35a46ce09cfb31ee220c8141a25e73e0b239b@seed.cosmos.cryptium.ch:46656,80a35a46ce09cfb31ee220c8141a25e73e0b239b@35.198.166.171:46656,032fa56301de335d835057fb6ad9f7ce2242a66d@165.227.236.213:46656"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also [ask other validators](https://riot.im/app/#/room/#cosmos_validators:matrix.org) for a persistent peer and add it under the `persistent_peers` key. For more information on seeds and peers, [read this](https://github.com/tendermint/tendermint/blob/develop/docs/using-tendermint.md#peers).
|
||||||
|
|
||||||
|
## Run a Full Node
|
||||||
|
|
||||||
|
Start the full node with this command:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiad start
|
||||||
|
```
|
||||||
|
|
||||||
|
Check that everything is running smoothly:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli status
|
||||||
|
```
|
||||||
|
|
||||||
|
View the status of the network with the [Cosmos Explorer](https://explorecosmos.network). Once your full node syncs up to the current block height, you should see it appear on the [list of full nodes](https://explorecosmos.network/validators). If it doesn't show up, that's ok--the Explorer does not connect to every node.
|
||||||
|
|
||||||
|
## Generate Keys
|
||||||
|
|
||||||
|
You'll need a private and public key pair \(a.k.a. `sk, pk` respectively\) to be able to receive funds, send txs, bond tx, etc.
|
||||||
|
|
||||||
|
To generate a new key \(default _ed25519_ elliptic curve\):
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli keys add <your_key_name>
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, you will have to create a passphrase. Save the _seed_ _phrase_ in a safe place in case you forget the password.
|
||||||
|
|
||||||
|
If you check your private keys, you'll now see `<your_key_name>`:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli keys show <your_key_name>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can see all your available keys by typing:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli keys list
|
||||||
|
```
|
||||||
|
|
||||||
|
View the validator pubkey for your node by typing:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiad tendermint show_validator
|
||||||
|
```
|
||||||
|
|
||||||
|
Save your address and pubkey to environment variables for later use:
|
||||||
|
|
||||||
|
```
|
||||||
|
MYADDR=<your_newly_generated_address>
|
||||||
|
MYPUBKEY=<your_newly_generated_public_key>
|
||||||
|
```
|
||||||
|
|
||||||
|
**WARNING:** We strongly recommend NOT using the same passphrase for multiple keys. The Tendermint team and the Interchain Foundation will not be responsible for the loss of funds.
|
||||||
|
|
||||||
|
## Get Tokens
|
||||||
|
|
||||||
|
The best way to get tokens is from the [Cosmos Testnet Faucet](https://faucetcosmos.network). If the faucet is not working for you, try asking [#cosmos-validators](https://riot.im/app/#/room/#cosmos-validators:matrix.org).
|
||||||
|
|
||||||
|
After receiving tokens to your address, you can view your account's balance by typing:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli account <your_newly_generated_address>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: When you query an account balance with zero tokens, you will get this error: `No account with address <your_newly_generated_address> was found in the state.` This is expected! We're working on improving our error messages.
|
||||||
|
|
||||||
|
## Send Tokens
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli send --amount=10faucetToken --chain-id=<name_of_testnet_chain> --name=<key_name> --to=<destination_address>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: The `--amount` flag accepts the format `--amount=<value|coin_name>`.
|
||||||
|
|
||||||
|
Now, view the updated balances of the origin and destination accounts:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli account <origin_address>
|
||||||
|
gaiacli account <destination_address>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also check your balance at a given block by using the `--block` flag:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli account <your_address> --block=<block_height>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run a Validator Node
|
||||||
|
|
||||||
|
[Validators](https://cosmos.network/validators) are responsible for committing new blocks to the blockchain through voting. A validator's stake is slashed if they become unavailable, double sign a transaction, or don't cast their votes. If you only want to run a full node, a VM in the cloud is fine. However, if you are want to become a validator for the Hub's `mainnet`, you should research hardened setups. Please read [Sentry Node Architecture](https://github.com/cosmos/cosmos/blob/master/VALIDATORS_FAQ.md#how-can-validators-protect-themselves-from-denial-of-service-attacks) to protect your node from DDOS and ensure high-availability. Also see the [technical requirements](https://github.com/cosmos/cosmos/blob/master/VALIDATORS_FAQ.md#technical-requirements)). There's also more info on our [website](https://cosmos.network/validators).
|
||||||
|
|
||||||
|
Your `pubkey` can be used to create a new validator by staking tokens. You can find your validator pubkey by running:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiad tendermint show_validator
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, craft your `gaiacli stake create-validator` command:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli stake create-validator --amount=5steak --pubkey=<your_node_pubkey> --address-validator=<your_address> --moniker=satoshi --chain-id=<name_of_the_testnet_chain> --name=<key_name>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can add more information to the validator, such as`--website`, `--keybase-sig`, or `--details`. Here's how:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli stake edit-validator --details="To the cosmos !" --website="https://cosmos.network"
|
||||||
|
```
|
||||||
|
|
||||||
|
View the validator's information with this command:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli stake validator --address-validator=<your_address> --chain-id=<name_of_the_testnet_chain>
|
||||||
|
```
|
||||||
|
|
||||||
|
To check that the validator is active, look for it here:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli advanced tendermint validator-set
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** To be in the validator set, you need to have more total voting power than the 100th validator.
|
||||||
|
|
||||||
|
## Delegating to a Validator
|
||||||
|
|
||||||
|
On the upcoming mainnet, you can delegate `atom` to a validator. These [delegators](https://cosmos.network/resources/delegators) can receive part of the validator's fee revenue. Read more about the [Cosmos Token Model](https://github.com/cosmos/cosmos/raw/master/Cosmos_Token_Model.pdf).
|
||||||
|
|
||||||
|
### Bond Tokens
|
||||||
|
|
||||||
|
On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond tokens to a testnet validator:
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli stake delegate --amount=10steak --address-delegator=<your_address> --address-validator=<bonded_validator_address> --name=<key_name> --chain-id=<name_of_testnet_chain>
|
||||||
|
```
|
||||||
|
|
||||||
|
While tokens are bonded, they are pooled with all the other bonded tokens in the network. Validators and delegators obtain a percentage of shares that equal their stake in this pool.
|
||||||
|
|
||||||
|
### Unbond Tokens
|
||||||
|
|
||||||
|
If for any reason the validator misbehaves, or you want to unbond a certain amount of tokens, use this following command. You can unbond a specific amount of`shares`\(eg:`12.1`\) or all of them \(`MAX`\).
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli stake unbond --address-delegator=<your_address> --address-validator=<bonded_validator_address> --shares=MAX --name=<key_name> --chain-id=<name_of_testnet_chain>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can check your balance and your stake delegation to see that the unbonding went through successfully.
|
||||||
|
|
||||||
|
```
|
||||||
|
gaiacli account <your_address>
|
||||||
|
gaiacli stake delegation --address-delegator=<your_address> --address-validator=<bonded_validator_address> --chain-id=<name_of_testnet_chain>
|
||||||
|
```
|
|
@ -0,0 +1,101 @@
|
||||||
|
# TESTNET STATUS
|
||||||
|
|
||||||
|
## *June 13, 2018, 17:00 EST* - Gaia-6002 is making blocks!
|
||||||
|
|
||||||
|
- Gaia-6002 is live and making blocks
|
||||||
|
- Absent validators have been slashed and revoked
|
||||||
|
- Currently live with 17 validators
|
||||||
|
|
||||||
|
## *June 13, 2018, 4:30 EST* - New Testnet Gaia-6002
|
||||||
|
|
||||||
|
- After fixing bugs from gaia-6001, especially [issue
|
||||||
|
#1197](https://github.com/cosmos/cosmos-sdk/issues/1197), we are announcing a
|
||||||
|
new testnet, Gaia-6002
|
||||||
|
- Gaia-6002 has the same genesis file as Gaia-6001, just with the chain-id
|
||||||
|
updated
|
||||||
|
- Update from previous testnet [here](https://github.com/cosmos/cosmos-sdk/tree/master/cmd/gaia/testnets#upgrading-from-previous-testnet)
|
||||||
|
|
||||||
|
## *June 13, 2018, 4:30 EST* - New Release
|
||||||
|
|
||||||
|
- Released gaia
|
||||||
|
[v0.19.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.19.0)
|
||||||
|
- Includes various bug-fixes for staking found on Gaia-6001
|
||||||
|
|
||||||
|
## *June 13, 2018, 2:30 EST* - Published Postmortem of Gaia-6001 failure
|
||||||
|
|
||||||
|
- A bug in the design of the staking data model caused a sanity check to fail
|
||||||
|
- Full writeup
|
||||||
|
[here](https://github.com/cosmos/cosmos-sdk/issues/1197#issuecomment-396823021)
|
||||||
|
|
||||||
|
## *June 10, 2018, 8:30 EST* - Gaia-6001 consensus failure
|
||||||
|
|
||||||
|
- Validator unbonding and revocation activity caused a consensus failure
|
||||||
|
- There is a bug in the staking module that must be fixed
|
||||||
|
- The team is taking its time to look into this and release a fix following a
|
||||||
|
proper protocol for hotfix upgrades to the testnet
|
||||||
|
- Please stay tuned!
|
||||||
|
|
||||||
|
## *June 9, 2018, 14:00 EST* - New Release
|
||||||
|
|
||||||
|
- Released gaia
|
||||||
|
[v0.18.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.18.0) with
|
||||||
|
update for Tendermint
|
||||||
|
[v0.20.0](https://github.com/tendermint/tendermint/releases/tag/v0.20.0)
|
||||||
|
- Includes bug fix for declaring candidacy from the command line
|
||||||
|
|
||||||
|
## *June 8, 2018, 23:30 EST* - Gaia-6001 is making blocks
|
||||||
|
|
||||||
|
- +2/3 of the voting power is finally online for Gaia-6001 and it is making
|
||||||
|
blocks!
|
||||||
|
- This is a momentous achievement - a successful asynchronous decentralized
|
||||||
|
testnet launch
|
||||||
|
- Congrats everyone!
|
||||||
|
|
||||||
|
## *June 8, 2018, 12:00 EST* - New Testnet Gaia-6001
|
||||||
|
|
||||||
|
- After some confusion around testnet deployment and a contention testnet
|
||||||
|
hardfork, a new genesis file and network was released for `gaia-6001`
|
||||||
|
|
||||||
|
## *June 7, 2018, 9:00 EST* - New Testnet Gaia-6000
|
||||||
|
|
||||||
|
- Released a new `genesis.json` file for `gaia-6000`
|
||||||
|
- Initial validators include those that were most active in
|
||||||
|
the gaia-5001 testnet
|
||||||
|
- Join the network via gaia `v0.18.0-rc0`
|
||||||
|
|
||||||
|
## *June 5, 2018, 21:00 EST* - New Release
|
||||||
|
|
||||||
|
- Released gaia
|
||||||
|
[v0.17.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.17.5)
|
||||||
|
with update for Tendermint
|
||||||
|
[v0.19.9](https://github.com/tendermint/tendermint/releases/tag/v0.19.9)
|
||||||
|
- Fixes many bugs!
|
||||||
|
- evidence gossipping
|
||||||
|
- mempool deadlock
|
||||||
|
- WAL panic
|
||||||
|
- memory leak
|
||||||
|
- Please update to this to put a stop to the rampant invalid evidence gossiping
|
||||||
|
:)
|
||||||
|
|
||||||
|
## *May 31, 2018, 14:00 EST* - New Release
|
||||||
|
|
||||||
|
- Released gaia
|
||||||
|
[v0.17.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.17.4) with update for Tendermint v0.19.7
|
||||||
|
- Fixes a WAL bug and some more
|
||||||
|
- Please update to this if you have trouble restarting a node
|
||||||
|
|
||||||
|
## *May 31, 2018, 2:00 EST* - Testnet Halt
|
||||||
|
|
||||||
|
- A validator equivocated last week and Evidence is being rampantly gossipped
|
||||||
|
- Peers that can't process the evidence (either too far behind or too far ahead) are disconnecting from the peers that
|
||||||
|
sent it, causing high peer turn-over
|
||||||
|
- The high peer turn-over may be causing a memory-leak, resulting in some nodes
|
||||||
|
crashing and the testnet halting
|
||||||
|
- We need to fix some issues in the EvidenceReactor to address this and also
|
||||||
|
investigate the possible memory-leak
|
||||||
|
|
||||||
|
## *May 29, 2018* - New Release
|
||||||
|
|
||||||
|
- Released v0.17.3 with update for Tendermint v0.19.6
|
||||||
|
- Fixes fast-sync bug
|
||||||
|
- Please update to this to sync with the testnet
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "1ebc5ca705b3ae1c06a0888ff1287ada82149dc3",
|
||||||
|
"ip": "138.68.77.24",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "adrian"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "default",
|
||||||
|
"address": "D9C12CB5186FE0018179742FD3110EE534C63460",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "c272ae3cff7558db2c6195eea38fd43fd08406dc",
|
||||||
|
"ip": "206.189.31.178",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "tJlZJWjOpYvRitYFTWNPTaUtvQVf+hoNjlfI84VPqvI="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "anton"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "default",
|
||||||
|
"address": "E766088FD171906289617F60BF0014C46F0F85EC",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "tJlZJWjOpYvRitYFTWNPTaUtvQVf+hoNjlfI84VPqvI="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "aef085c4bfed0c1ffc6705f2e1e3bf85e5164600",
|
||||||
|
"ip": "45.77.53.208",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "RpX+xkwnCNw5DpBelscz4//TiODyC9RDiyIuD6NEwx0="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "aurel"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "aurel",
|
||||||
|
"address": "10B0899E05A486AE4E5589C39587DF7E9A185872",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "RpX+xkwnCNw5DpBelscz4//TiODyC9RDiyIuD6NEwx0="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "b0dd378c3fbc4c156cd6d302a799f0d2e4227201",
|
||||||
|
"ip": "159.89.121.174",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "0aNTDL49987ZNRi3FtJIi0jk93ybHuYg1FjWrfP9H2o="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "bucky"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "bucky",
|
||||||
|
"address": "935E48ED79F1006ED135553768E1D9A768747CF6",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "0aNTDL49987ZNRi3FtJIi0jk93ybHuYg1FjWrfP9H2o="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "e25603602d8cf8542570ad0e311d50f55f497f85",
|
||||||
|
"ip": "158.69.63.13",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "dcmCn+RZTBdwbCa4YqSnw/Va7xQloBw6vF87ItLwdM0="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "cwgoes"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "cwgoes",
|
||||||
|
"address": "328FBB8EA315D070DF908982A5F91A3618001D20",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "dcmCn+RZTBdwbCa4YqSnw/Va7xQloBw6vF87ItLwdM0="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "aabf05a67b2f399807dc602d05bf97b0ed283ac2",
|
||||||
|
"ip": "116.62.62.39",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "7SaH/LyM+qdz9ovD/pvqIf2q7LC7tc5v0ZJxsA2CGTw="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "iris"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "=suyu",
|
||||||
|
"address": "4B5BE759EB23B0D76C6A60636BD0E3111178794E",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "7SaH/LyM+qdz9ovD/pvqIf2q7LC7tc5v0ZJxsA2CGTw="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "79466a03e9d4b4648a7dd8cead1fa7121ce76ee3",
|
||||||
|
"ip": "34.235.130.1",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "SW12+WpGKUCO9oT2CV0CD5kUclbXjJHV1MjerLWB7Oc="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "lino"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "lino",
|
||||||
|
"address": "5A007B81A25AF34B829B79DA508A26E12180BCDB",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "SW12+WpGKUCO9oT2CV0CD5kUclbXjJHV1MjerLWB7Oc="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "adb290585a2753bf1a520c76802b0dab3dffa895",
|
||||||
|
"ip": "34.201.21.179",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "pY7eLF0Ez3yq495kIjag8mD67Q131np/ssagpEvlV2A="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "pbostrom"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "default",
|
||||||
|
"address": "109720515B4F8C0858DA3521E448262334534FFD",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "pY7eLF0Ez3yq495kIjag8mD67Q131np/ssagpEvlV2A="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "678503e6c8f50db7279c7da3cb9b072aac4bc0d5",
|
||||||
|
"ip": "35.193.188.125",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "RMwWTZsVdkq1heicNJb2fosy9Fls4NHxAHReiJvHl+8="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "polsdam"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "poldsam",
|
||||||
|
"address": "FA929191B04C5DB222AFC6F15C63EF48CCC864C5",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "RMwWTZsVdkq1heicNJb2fosy9Fls4NHxAHReiJvHl+8="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "3519f05985394107e0b2e285361b7e012adb1113",
|
||||||
|
"ip": "54.209.118.64",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "vq0V0BjpmIh6WyNnFpMaO5LyUK2FamkNt65eJYa5AaQ="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "staked"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "default",
|
||||||
|
"address": "935E04662697134905706A4CCDB822AC6FC11C2E",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "vq0V0BjpmIh6WyNnFpMaO5LyUK2FamkNt65eJYa5AaQ="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "8a2802fb25d352f3e7e277559a4f683780c3ef22",
|
||||||
|
"ip": "167.99.191.184",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "NjjEQKUsq8F0gWxl3BoU2Li5n7hEz9H/LX80rfMxVyE="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "zach",
|
||||||
|
"address": "9D5723057702E2090405AB5D3B48C45B9ABF4377",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "NjjEQKUsq8F0gWxl3BoU2Li5n7hEz9H/LX80rfMxVyE="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"node_id": "30b45459e4881680c0ef1750fde136fefa6c3b98",
|
||||||
|
"ip": "35.184.182.143",
|
||||||
|
"validator": {
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "CDF/8aD8Lt+ikR3LyCg9c7DwWBA51NH+MUkH7tzxrfY="
|
||||||
|
},
|
||||||
|
"power": 100,
|
||||||
|
"name": "zaki"
|
||||||
|
},
|
||||||
|
"app_gen_tx": {
|
||||||
|
"name": "zaki",
|
||||||
|
"address": "ECE57661F0CDCF28EED257B72F86240E57F4A612",
|
||||||
|
"pub_key": {
|
||||||
|
"type": "AC26791624DE60",
|
||||||
|
"value": "CDF/8aD8Lt+ikR3LyCg9c7DwWBA51NH+MUkH7tzxrfY="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -78,7 +78,7 @@ window. Here run:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
basecli init --node=tcp://localhost:46657 --genesis=$HOME/.basecoin/genesis.json
|
basecli init --node=tcp://localhost:26657 --genesis=$HOME/.basecoin/genesis.json
|
||||||
|
|
||||||
If you provide the genesis file to basecli, it can calculate the proper
|
If you provide the genesis file to basecli, it can calculate the proper
|
||||||
chainID and validator hash. Basecli needs to get this information from
|
chainID and validator hash. Basecli needs to get this information from
|
||||||
|
|
|
@ -49,7 +49,7 @@ initialize the light-client and send a transaction:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
countercli init --node=tcp://localhost:46657 --genesis=$HOME/.counter/genesis.json
|
countercli init --node=tcp://localhost:26657 --genesis=$HOME/.counter/genesis.json
|
||||||
|
|
||||||
YOU=$(countercli keys get friend | awk '{print $2}')
|
YOU=$(countercli keys get friend | awk '{print $2}')
|
||||||
countercli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1
|
countercli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1
|
||||||
|
|
|
@ -39,18 +39,18 @@ and ports. It should look like:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
proxy_app = "tcp://127.0.0.1:46668"
|
proxy_app = "tcp://127.0.0.1:26668"
|
||||||
moniker = "anonymous"
|
moniker = "anonymous"
|
||||||
fast_sync = true
|
fast_sync = true
|
||||||
db_backend = "leveldb"
|
db_backend = "leveldb"
|
||||||
log_level = "state:info,*:error"
|
log_level = "state:info,*:error"
|
||||||
|
|
||||||
[rpc]
|
[rpc]
|
||||||
laddr = "tcp://0.0.0.0:46667"
|
laddr = "tcp://0.0.0.0:26667"
|
||||||
|
|
||||||
[p2p]
|
[p2p]
|
||||||
laddr = "tcp://0.0.0.0:46666"
|
laddr = "tcp://0.0.0.0:26666"
|
||||||
seeds = "0.0.0.0:46656"
|
seeds = "0.0.0.0:26656"
|
||||||
|
|
||||||
Start Nodes
|
Start Nodes
|
||||||
-----------
|
-----------
|
||||||
|
@ -69,14 +69,14 @@ account:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaia client init --chain-id=gaia-test --node=tcp://localhost:46657
|
gaia client init --chain-id=gaia-test --node=tcp://localhost:26657
|
||||||
gaia client query account 5D93A6059B6592833CBC8FA3DA90EE0382198985
|
gaia client query account 5D93A6059B6592833CBC8FA3DA90EE0382198985
|
||||||
|
|
||||||
To see what tendermint considers the validator set is, use:
|
To see what tendermint considers the validator set is, use:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
curl localhost:46657/validators
|
curl localhost:26657/validators
|
||||||
|
|
||||||
and compare the information in this file: ``~/.gaia1/priv_validator.json``. The ``address`` and ``pub_key`` fields should match.
|
and compare the information in this file: ``~/.gaia1/priv_validator.json``. The ``address`` and ``pub_key`` fields should match.
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ Finally, let's initialize the gaia client to interact with the testnet:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
gaia client init --chain-id=gaia-1 --node=tcp://localhost:46657
|
gaia client init --chain-id=gaia-1 --node=tcp://localhost:26657
|
||||||
|
|
||||||
and check our balance:
|
and check our balance:
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ paths:
|
||||||
type: string
|
type: string
|
||||||
listen_addr:
|
listen_addr:
|
||||||
type: string
|
type: string
|
||||||
example: 192.168.56.1:46656
|
example: 192.168.56.1:26656
|
||||||
version:
|
version:
|
||||||
description: Tendermint version
|
description: Tendermint version
|
||||||
type: string
|
type: string
|
||||||
|
@ -102,7 +102,7 @@ paths:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: 12 word Seed
|
description: 16 word Seed
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
/keys/{name}:
|
/keys/{name}:
|
||||||
|
@ -204,7 +204,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: address
|
name: address
|
||||||
description: Account address
|
description: Account address in bech32 format
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
get:
|
get:
|
||||||
|
@ -222,7 +222,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: address
|
name: address
|
||||||
description: Account address
|
description: Account address in bech32 format
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
post:
|
post:
|
||||||
|
@ -255,18 +255,6 @@ paths:
|
||||||
description: Tx was send and will probably be added to the next block
|
description: Tx was send and will probably be added to the next block
|
||||||
400:
|
400:
|
||||||
description: The Tx was malformated
|
description: The Tx was malformated
|
||||||
/accounts/{address}/nonce:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: address
|
|
||||||
description: Account address
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
get:
|
|
||||||
summary: Get the nonce for a certain account
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Plaintext nonce i.e. "4" defaults to "0"
|
|
||||||
/blocks/latest:
|
/blocks/latest:
|
||||||
get:
|
get:
|
||||||
summary: Get the latest block
|
summary: Get the latest block
|
||||||
|
@ -304,9 +292,14 @@ paths:
|
||||||
200:
|
200:
|
||||||
description: The validator set at the latest block height
|
description: The validator set at the latest block height
|
||||||
schema:
|
schema:
|
||||||
type: array
|
type: object
|
||||||
items:
|
properties:
|
||||||
$ref: "#/definitions/Delegate"
|
block_height:
|
||||||
|
type: number
|
||||||
|
validators:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/Validator"
|
||||||
/validatorsets/{height}:
|
/validatorsets/{height}:
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
|
@ -322,9 +315,14 @@ paths:
|
||||||
200:
|
200:
|
||||||
description: The validator set at a specific block height
|
description: The validator set at a specific block height
|
||||||
schema:
|
schema:
|
||||||
type: array
|
type: object
|
||||||
items:
|
properties:
|
||||||
$ref: "#/definitions/Delegate"
|
block_height:
|
||||||
|
type: number
|
||||||
|
validators:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/Validator"
|
||||||
404:
|
404:
|
||||||
description: Block at height not available
|
description: Block at height not available
|
||||||
# /txs:
|
# /txs:
|
||||||
|
@ -549,7 +547,20 @@ paths:
|
||||||
definitions:
|
definitions:
|
||||||
Address:
|
Address:
|
||||||
type: string
|
type: string
|
||||||
example: DF096FDE8D380FA5B2AD20DB2962C82DDEA1ED9B
|
description: bech32 encoded addres
|
||||||
|
example: cosmosaccaddr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
||||||
|
ValidatorAddress:
|
||||||
|
type: string
|
||||||
|
description: bech32 encoded addres
|
||||||
|
example: cosmosvaladdr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
||||||
|
PubKey:
|
||||||
|
type: string
|
||||||
|
description: bech32 encoded public key
|
||||||
|
example: cosmosaccpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
||||||
|
ValidatorPubKey:
|
||||||
|
type: string
|
||||||
|
description: bech32 encoded public key
|
||||||
|
example: cosmosvalpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
|
||||||
Coins:
|
Coins:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -652,16 +663,6 @@ definitions:
|
||||||
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
||||||
Pubkey:
|
Pubkey:
|
||||||
$ref: "#/definitions/PubKey"
|
$ref: "#/definitions/PubKey"
|
||||||
PubKey:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
enum:
|
|
||||||
- ed25519
|
|
||||||
data:
|
|
||||||
type: string
|
|
||||||
example: 81B11E717789600CC192B26F452A983DF13B985EE75ABD9DD9E68D7BA007A958
|
|
||||||
Account:
|
Account:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -753,17 +754,19 @@ definitions:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
type: object
|
type: object
|
||||||
Delegate:
|
Validator:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
address:
|
||||||
|
$ref: '#/definitions/ValidatorAddress'
|
||||||
pub_key:
|
pub_key:
|
||||||
$ref: "#/definitions/PubKey"
|
$ref: "#/definitions/ValidatorPubKey"
|
||||||
power:
|
power:
|
||||||
type: number
|
type: number
|
||||||
example: 1000
|
example: 1000
|
||||||
name:
|
accum:
|
||||||
type: string
|
type: number
|
||||||
example: "159.89.3.34"
|
example: 1000
|
||||||
# Added by API Auto Mocking Plugin
|
# Added by API Auto Mocking Plugin
|
||||||
host: virtserver.swaggerhub.com
|
host: virtserver.swaggerhub.com
|
||||||
basePath: /faboweb1/Cosmos-LCD-2/1.0.0
|
basePath: /faboweb1/Cosmos-LCD-2/1.0.0
|
||||||
|
|
|
@ -232,12 +232,14 @@ a standard form:
|
||||||
type StdSignature struct {
|
type StdSignature struct {
|
||||||
crypto.PubKey // optional
|
crypto.PubKey // optional
|
||||||
crypto.Signature
|
crypto.Signature
|
||||||
Sequence int64
|
AccountNumber int64
|
||||||
|
Sequence int64
|
||||||
}
|
}
|
||||||
|
|
||||||
It contains the signature itself, as well as the corresponding account's
|
It contains the signature itself, as well as the corresponding account's account and
|
||||||
sequence number. The sequence number is expected to increment every time a
|
sequence numbers. The sequence number is expected to increment every time a
|
||||||
message is signed by a given account. This prevents "replay attacks", where
|
message is signed by a given account. The account number stays the same and is assigned
|
||||||
|
when the account is first generated. These prevent "replay attacks", where
|
||||||
the same message could be executed over and over again.
|
the same message could be executed over and over again.
|
||||||
|
|
||||||
The ``StdSignature`` can also optionally include the public key for verifying the
|
The ``StdSignature`` can also optionally include the public key for verifying the
|
||||||
|
|
|
@ -291,7 +291,7 @@ To confirm for certain the new validator is active, ask the tendermint node:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
curl localhost:46657/validators
|
curl localhost:26657/validators
|
||||||
|
|
||||||
If you now kill either node, blocks will stop streaming in, because
|
If you now kill either node, blocks will stop streaming in, because
|
||||||
there aren't enough validators online. Turn it back on and they will
|
there aren't enough validators online. Turn it back on and they will
|
||||||
|
|
|
@ -66,7 +66,7 @@ To confirm for certain the new validator is active, check tendermint:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
curl localhost:46657/validators
|
curl localhost:26657/validators
|
||||||
|
|
||||||
Finally, to relinquish all your power, unbond some coins. You should see your VotingPower reduce and your account balance increase.
|
Finally, to relinquish all your power, unbond some coins. You should see your VotingPower reduce and your account balance increase.
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -145,6 +146,7 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
|
||||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||||
}
|
}
|
||||||
|
acc.AccountNumber = app.accountMapper.GetNextAccountNumber(ctx)
|
||||||
app.accountMapper.SetAccount(ctx, acc)
|
app.accountMapper.SetAccount(ctx, acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +157,7 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom logic for state export
|
// Custom logic for state export
|
||||||
func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
func (app *BasecoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||||
ctx := app.NewContext(true, abci.Header{})
|
ctx := app.NewContext(true, abci.Header{})
|
||||||
|
|
||||||
// iterate to get the accounts
|
// iterate to get the accounts
|
||||||
|
@ -173,5 +175,10 @@ func (app *BasecoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
|
||||||
genState := types.GenesisState{
|
genState := types.GenesisState{
|
||||||
Accounts: accounts,
|
Accounts: accounts,
|
||||||
}
|
}
|
||||||
return wire.MarshalJSONIndent(app.cdc, genState)
|
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
validators = stake.WriteValidators(ctx, app.stakeKeeper)
|
||||||
|
return appState, validators, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -13,8 +11,6 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
@ -23,74 +19,10 @@ import (
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Construct some global addrs and txs for tests.
|
|
||||||
var (
|
|
||||||
chainID = "" // TODO
|
|
||||||
|
|
||||||
accName = "foobart"
|
|
||||||
|
|
||||||
priv1 = crypto.GenPrivKeyEd25519()
|
|
||||||
addr1 = priv1.PubKey().Address()
|
|
||||||
priv2 = crypto.GenPrivKeyEd25519()
|
|
||||||
addr2 = priv2.PubKey().Address()
|
|
||||||
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
|
||||||
priv4 = crypto.GenPrivKeyEd25519()
|
|
||||||
addr4 = priv4.PubKey().Address()
|
|
||||||
coins = sdk.Coins{{"foocoin", 10}}
|
|
||||||
halfCoins = sdk.Coins{{"foocoin", 5}}
|
|
||||||
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
|
|
||||||
fee = auth.StdFee{
|
|
||||||
sdk.Coins{{"foocoin", 0}},
|
|
||||||
100000,
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg1 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
|
||||||
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg2 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
bank.NewOutput(addr2, halfCoins),
|
|
||||||
bank.NewOutput(addr3, halfCoins),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg3 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{
|
|
||||||
bank.NewInput(addr1, coins),
|
|
||||||
bank.NewInput(addr4, coins),
|
|
||||||
},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
bank.NewOutput(addr2, coins),
|
|
||||||
bank.NewOutput(addr3, coins),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg4 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{
|
|
||||||
bank.NewInput(addr2, coins),
|
|
||||||
},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
bank.NewOutput(addr1, coins),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg5 = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{
|
|
||||||
bank.NewInput(addr1, manyCoins),
|
|
||||||
},
|
|
||||||
Outputs: []bank.Output{
|
|
||||||
bank.NewOutput(addr2, manyCoins),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error {
|
func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error {
|
||||||
genaccs := make([]*types.GenesisAccount, len(accs))
|
genaccs := make([]*types.GenesisAccount, len(accs))
|
||||||
for i, acc := range accs {
|
for i, acc := range accs {
|
||||||
genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, accName})
|
genaccs[i] = types.NewGenesisAccount(&types.AppAccount{acc, "foobart"})
|
||||||
}
|
}
|
||||||
|
|
||||||
genesisState := types.GenesisState{
|
genesisState := types.GenesisState{
|
||||||
|
@ -111,79 +43,11 @@ func setGenesis(bapp *BasecoinApp, accs ...auth.BaseAccount) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loggerAndDB() (log.Logger, dbm.DB) {
|
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
|
||||||
db := dbm.NewMemDB()
|
|
||||||
return logger, db
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBasecoinApp() *BasecoinApp {
|
|
||||||
logger, db := loggerAndDB()
|
|
||||||
return NewBasecoinApp(logger, db)
|
|
||||||
}
|
|
||||||
|
|
||||||
//_______________________________________________________________________
|
//_______________________________________________________________________
|
||||||
|
|
||||||
func TestMsgs(t *testing.T) {
|
|
||||||
bapp := newBasecoinApp()
|
|
||||||
require.Nil(t, setGenesis(bapp))
|
|
||||||
|
|
||||||
msgs := []struct {
|
|
||||||
msg sdk.Msg
|
|
||||||
}{
|
|
||||||
{sendMsg1},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, m := range msgs {
|
|
||||||
// Run a CheckDeliver
|
|
||||||
SignCheckDeliver(t, bapp, m.msg, []int64{int64(i)}, false, priv1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSortGenesis(t *testing.T) {
|
|
||||||
logger, db := loggerAndDB()
|
|
||||||
bapp := NewBasecoinApp(logger, db)
|
|
||||||
|
|
||||||
// Note the order: the coins are unsorted!
|
|
||||||
coinDenom1, coinDenom2 := "foocoin", "barcoin"
|
|
||||||
|
|
||||||
genState := fmt.Sprintf(`{
|
|
||||||
"accounts": [{
|
|
||||||
"address": "%s",
|
|
||||||
"coins": [
|
|
||||||
{
|
|
||||||
"denom": "%s",
|
|
||||||
"amount": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"denom": "%s",
|
|
||||||
"amount": 20
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
}`, addr1.String(), coinDenom1, coinDenom2)
|
|
||||||
|
|
||||||
// Initialize the chain
|
|
||||||
vals := []abci.Validator{}
|
|
||||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: []byte(genState)})
|
|
||||||
bapp.Commit()
|
|
||||||
|
|
||||||
// Unsorted coins means invalid
|
|
||||||
err := sendMsg5.ValidateBasic()
|
|
||||||
require.Equal(t, sdk.CodeInvalidCoins, err.Code(), err.ABCILog())
|
|
||||||
|
|
||||||
// Sort coins, should be valid
|
|
||||||
sendMsg5.Inputs[0].Coins.Sort()
|
|
||||||
sendMsg5.Outputs[0].Coins.Sort()
|
|
||||||
err = sendMsg5.ValidateBasic()
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Ensure we can send
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg5, []int64{0}, true, priv1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenesis(t *testing.T) {
|
func TestGenesis(t *testing.T) {
|
||||||
logger, db := loggerAndDB()
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
||||||
|
db := dbm.NewMemDB()
|
||||||
bapp := NewBasecoinApp(logger, db)
|
bapp := NewBasecoinApp(logger, db)
|
||||||
|
|
||||||
// Construct some genesis bytes to reflect basecoin/types/AppAccount
|
// Construct some genesis bytes to reflect basecoin/types/AppAccount
|
||||||
|
@ -211,318 +75,3 @@ func TestGenesis(t *testing.T) {
|
||||||
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
||||||
assert.Equal(t, acc, res1)
|
assert.Equal(t, acc, res1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMsgChangePubKey(t *testing.T) {
|
|
||||||
|
|
||||||
bapp := newBasecoinApp()
|
|
||||||
|
|
||||||
// Construct some genesis bytes to reflect basecoin/types/AppAccount
|
|
||||||
// Give 77 foocoin to the first key
|
|
||||||
coins, err := sdk.ParseCoins("77foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
baseAcc := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
err = setGenesis(bapp, baseAcc)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, baseAcc, res1.(*types.AppAccount).BaseAccount)
|
|
||||||
|
|
||||||
// Run a CheckDeliver
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, bapp, addr1, "67foocoin")
|
|
||||||
CheckBalance(t, bapp, addr2, "10foocoin")
|
|
||||||
|
|
||||||
changePubKeyMsg := auth.MsgChangeKey{
|
|
||||||
Address: addr1,
|
|
||||||
NewPubKey: priv2.PubKey(),
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
|
||||||
acc := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
|
||||||
|
|
||||||
// send a MsgChangePubKey
|
|
||||||
SignCheckDeliver(t, bapp, changePubKeyMsg, []int64{1}, true, priv1)
|
|
||||||
acc = bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
|
||||||
|
|
||||||
assert.True(t, priv2.PubKey().Equals(acc.GetPubKey()))
|
|
||||||
|
|
||||||
// signing a SendMsg with the old privKey should be an auth error
|
|
||||||
tx := genTx(sendMsg1, []int64{2}, priv1)
|
|
||||||
res := bapp.Deliver(tx)
|
|
||||||
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
|
|
||||||
|
|
||||||
// resigning the tx with the new correct priv key should work
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{2}, true, priv2)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, bapp, addr1, "57foocoin")
|
|
||||||
CheckBalance(t, bapp, addr2, "20foocoin")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgSendWithAccounts(t *testing.T) {
|
|
||||||
bapp := newBasecoinApp()
|
|
||||||
|
|
||||||
// Construct some genesis bytes to reflect basecoin/types/AppAccount
|
|
||||||
// Give 77 foocoin to the first key
|
|
||||||
coins, err := sdk.ParseCoins("77foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
baseAcc := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
err = setGenesis(bapp, baseAcc)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, baseAcc, res1.(*types.AppAccount).BaseAccount)
|
|
||||||
|
|
||||||
// Run a CheckDeliver
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, bapp, addr1, "67foocoin")
|
|
||||||
CheckBalance(t, bapp, addr2, "10foocoin")
|
|
||||||
|
|
||||||
// Delivering again should cause replay error
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, false, priv1)
|
|
||||||
|
|
||||||
// bumping the txnonce number without resigning should be an auth error
|
|
||||||
tx := genTx(sendMsg1, []int64{0}, priv1)
|
|
||||||
tx.Signatures[0].Sequence = 1
|
|
||||||
res := bapp.Deliver(tx)
|
|
||||||
|
|
||||||
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
|
|
||||||
|
|
||||||
// resigning the tx with the bumped sequence should work
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{1}, true, priv1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgSendMultipleOut(t *testing.T) {
|
|
||||||
bapp := newBasecoinApp()
|
|
||||||
|
|
||||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
acc1 := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
acc2 := auth.BaseAccount{
|
|
||||||
Address: addr2,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
err = setGenesis(bapp, acc1, acc2)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg2, []int64{0}, true, priv1)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, bapp, addr1, "32foocoin")
|
|
||||||
CheckBalance(t, bapp, addr2, "47foocoin")
|
|
||||||
CheckBalance(t, bapp, addr3, "5foocoin")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSengMsgMultipleInOut(t *testing.T) {
|
|
||||||
bapp := newBasecoinApp()
|
|
||||||
|
|
||||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
acc1 := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
acc2 := auth.BaseAccount{
|
|
||||||
Address: addr2,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
acc4 := auth.BaseAccount{
|
|
||||||
Address: addr4,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = setGenesis(bapp, acc1, acc2, acc4)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
// CheckDeliver
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg3, []int64{0, 0}, true, priv1, priv4)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, bapp, addr1, "32foocoin")
|
|
||||||
CheckBalance(t, bapp, addr4, "32foocoin")
|
|
||||||
CheckBalance(t, bapp, addr2, "52foocoin")
|
|
||||||
CheckBalance(t, bapp, addr3, "10foocoin")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgSendDependent(t *testing.T) {
|
|
||||||
bapp := newBasecoinApp()
|
|
||||||
|
|
||||||
genCoins, err := sdk.ParseCoins("42foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
acc1 := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: genCoins,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
err = setGenesis(bapp, acc1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
err = setGenesis(bapp, acc1)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
// CheckDeliver
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, bapp, addr1, "32foocoin")
|
|
||||||
CheckBalance(t, bapp, addr2, "10foocoin")
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
SignCheckDeliver(t, bapp, sendMsg4, []int64{0}, true, priv2)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
CheckBalance(t, bapp, addr1, "42foocoin")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgQuiz(t *testing.T) {
|
|
||||||
bapp := newBasecoinApp()
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
// Construct some genesis bytes to reflect basecoin/types/AppAccount
|
|
||||||
baseAcc := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: nil,
|
|
||||||
}
|
|
||||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
genesisState := map[string]interface{}{
|
|
||||||
"accounts": []*types.GenesisAccount{
|
|
||||||
types.NewGenesisAccount(acc1),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Initialize the chain (nil)
|
|
||||||
vals := []abci.Validator{}
|
|
||||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
|
||||||
bapp.Commit()
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, acc1, res1)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIBCMsgs(t *testing.T) {
|
|
||||||
bapp := newBasecoinApp()
|
|
||||||
|
|
||||||
sourceChain := "source-chain"
|
|
||||||
destChain := "dest-chain"
|
|
||||||
|
|
||||||
baseAcc := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
|
||||||
|
|
||||||
err := setGenesis(bapp, baseAcc)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, acc1, res1)
|
|
||||||
|
|
||||||
packet := ibc.IBCPacket{
|
|
||||||
SrcAddr: addr1,
|
|
||||||
DestAddr: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
SrcChain: sourceChain,
|
|
||||||
DestChain: destChain,
|
|
||||||
}
|
|
||||||
|
|
||||||
transferMsg := ibc.IBCTransferMsg{
|
|
||||||
IBCPacket: packet,
|
|
||||||
}
|
|
||||||
|
|
||||||
receiveMsg := ibc.IBCReceiveMsg{
|
|
||||||
IBCPacket: packet,
|
|
||||||
Relayer: addr1,
|
|
||||||
Sequence: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
SignCheckDeliver(t, bapp, transferMsg, []int64{0}, true, priv1)
|
|
||||||
CheckBalance(t, bapp, addr1, "")
|
|
||||||
SignCheckDeliver(t, bapp, transferMsg, []int64{1}, false, priv1)
|
|
||||||
SignCheckDeliver(t, bapp, receiveMsg, []int64{2}, true, priv1)
|
|
||||||
CheckBalance(t, bapp, addr1, "10foocoin")
|
|
||||||
SignCheckDeliver(t, bapp, receiveMsg, []int64{3}, false, priv1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) auth.StdTx {
|
|
||||||
sigs := make([]auth.StdSignature, len(priv))
|
|
||||||
for i, p := range priv {
|
|
||||||
sigs[i] = auth.StdSignature{
|
|
||||||
PubKey: p.PubKey(),
|
|
||||||
Signature: p.Sign(auth.StdSignBytes(chainID, seq, fee, msg)),
|
|
||||||
Sequence: seq[i],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return auth.NewStdTx(msg, fee, sigs)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
|
|
||||||
|
|
||||||
// Sign the tx
|
|
||||||
tx := genTx(msg, seq, priv...)
|
|
||||||
// Run a Check
|
|
||||||
res := bapp.Check(tx)
|
|
||||||
if expPass {
|
|
||||||
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
} else {
|
|
||||||
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
res = bapp.Deliver(tx)
|
|
||||||
if expPass {
|
|
||||||
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
} else {
|
|
||||||
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
}
|
|
||||||
bapp.EndBlock(abci.RequestEndBlock{})
|
|
||||||
//bapp.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckBalance(t *testing.T, bapp *BasecoinApp, addr sdk.Address, balExpected string) {
|
|
||||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
|
||||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr)
|
|
||||||
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -27,7 +28,7 @@ func main() {
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
|
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
|
||||||
server.ConstructAppCreator(newApp, "basecoin"),
|
server.ConstructAppCreator(newApp, "basecoin"),
|
||||||
server.ConstructAppExporter(exportAppState, "basecoin"))
|
server.ConstructAppExporter(exportAppStateAndTMValidators, "basecoin"))
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
||||||
|
@ -39,7 +40,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
||||||
return app.NewBasecoinApp(logger, db)
|
return app.NewBasecoinApp(logger, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
|
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
bapp := app.NewBasecoinApp(logger, db)
|
bapp := app.NewBasecoinApp(logger, db)
|
||||||
return bapp.ExportAppStateJSON()
|
return bapp.ExportAppStateAndValidators()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -154,7 +155,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom logic for state export
|
// Custom logic for state export
|
||||||
func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err error) {
|
func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||||
ctx := app.NewContext(true, abci.Header{})
|
ctx := app.NewContext(true, abci.Header{})
|
||||||
|
|
||||||
// iterate to get the accounts
|
// iterate to get the accounts
|
||||||
|
@ -174,5 +175,9 @@ func (app *DemocoinApp) ExportAppStateJSON() (appState json.RawMessage, err erro
|
||||||
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
|
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
|
||||||
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
|
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
|
||||||
}
|
}
|
||||||
return wire.MarshalJSONIndent(app.cdc, genState)
|
appState, err = wire.MarshalJSONIndent(app.cdc, genState)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return appState, validators, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -10,12 +9,8 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
||||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
|
||||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/pow"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/ibc"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
crypto "github.com/tendermint/go-crypto"
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
@ -23,101 +18,9 @@ import (
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Construct some global addrs and txs for tests.
|
func TestGenesis(t *testing.T) {
|
||||||
var (
|
|
||||||
chainID = "" // TODO
|
|
||||||
|
|
||||||
priv1 = crypto.GenPrivKeyEd25519()
|
|
||||||
addr1 = priv1.PubKey().Address()
|
|
||||||
addr2 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
|
||||||
coins = sdk.Coins{{"foocoin", 10}}
|
|
||||||
fee = auth.StdFee{
|
|
||||||
sdk.Coins{{"foocoin", 0}},
|
|
||||||
1000000,
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMsg = bank.MsgSend{
|
|
||||||
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
|
|
||||||
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
|
|
||||||
}
|
|
||||||
|
|
||||||
quizMsg1 = cool.MsgQuiz{
|
|
||||||
Sender: addr1,
|
|
||||||
CoolAnswer: "icecold",
|
|
||||||
}
|
|
||||||
|
|
||||||
quizMsg2 = cool.MsgQuiz{
|
|
||||||
Sender: addr1,
|
|
||||||
CoolAnswer: "badvibesonly",
|
|
||||||
}
|
|
||||||
|
|
||||||
setTrendMsg1 = cool.MsgSetTrend{
|
|
||||||
Sender: addr1,
|
|
||||||
Cool: "icecold",
|
|
||||||
}
|
|
||||||
|
|
||||||
setTrendMsg2 = cool.MsgSetTrend{
|
|
||||||
Sender: addr1,
|
|
||||||
Cool: "badvibesonly",
|
|
||||||
}
|
|
||||||
|
|
||||||
setTrendMsg3 = cool.MsgSetTrend{
|
|
||||||
Sender: addr1,
|
|
||||||
Cool: "warmandkind",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func loggerAndDB() (log.Logger, dbm.DB) {
|
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
return logger, db
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDemocoinApp() *DemocoinApp {
|
|
||||||
logger, db := loggerAndDB()
|
|
||||||
return NewDemocoinApp(logger, db)
|
|
||||||
}
|
|
||||||
|
|
||||||
//_______________________________________________________________________
|
|
||||||
|
|
||||||
func TestMsgs(t *testing.T) {
|
|
||||||
bapp := newDemocoinApp()
|
|
||||||
|
|
||||||
msgs := []struct {
|
|
||||||
msg sdk.Msg
|
|
||||||
}{
|
|
||||||
{sendMsg},
|
|
||||||
{quizMsg1},
|
|
||||||
{setTrendMsg1},
|
|
||||||
}
|
|
||||||
|
|
||||||
sequences := []int64{0}
|
|
||||||
for i, m := range msgs {
|
|
||||||
sig := priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, m.msg))
|
|
||||||
tx := auth.NewStdTx(m.msg, fee, []auth.StdSignature{{
|
|
||||||
PubKey: priv1.PubKey(),
|
|
||||||
Signature: sig,
|
|
||||||
}})
|
|
||||||
|
|
||||||
// just marshal/unmarshal!
|
|
||||||
txBytes, err := bapp.cdc.MarshalBinary(tx)
|
|
||||||
require.NoError(t, err, "i: %v", i)
|
|
||||||
|
|
||||||
// Run a Check
|
|
||||||
cres := bapp.CheckTx(txBytes)
|
|
||||||
assert.Equal(t, sdk.CodeUnknownAddress,
|
|
||||||
sdk.CodeType(cres.Code), "i: %v, log: %v", i, cres.Log)
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
dres := bapp.DeliverTx(txBytes)
|
|
||||||
assert.Equal(t, sdk.CodeUnknownAddress,
|
|
||||||
sdk.CodeType(dres.Code), "i: %v, log: %v", i, dres.Log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenesis(t *testing.T) {
|
|
||||||
logger, db := loggerAndDB()
|
|
||||||
bapp := NewDemocoinApp(logger, db)
|
bapp := NewDemocoinApp(logger, db)
|
||||||
|
|
||||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
||||||
|
@ -156,272 +59,3 @@ func TestGenesis(t *testing.T) {
|
||||||
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
res1 = bapp.accountMapper.GetAccount(ctx, baseAcc.Address)
|
||||||
assert.Equal(t, acc, res1)
|
assert.Equal(t, acc, res1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMsgSendWithAccounts(t *testing.T) {
|
|
||||||
bapp := newDemocoinApp()
|
|
||||||
|
|
||||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
|
||||||
// Give 77 foocoin to the first key
|
|
||||||
coins, err := sdk.ParseCoins("77foocoin")
|
|
||||||
require.Nil(t, err)
|
|
||||||
baseAcc := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
genesisState := map[string]interface{}{
|
|
||||||
"accounts": []*types.GenesisAccount{
|
|
||||||
types.NewGenesisAccount(acc1),
|
|
||||||
},
|
|
||||||
"cool": map[string]string{
|
|
||||||
"trend": "ice-cold",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Initialize the chain
|
|
||||||
vals := []abci.Validator{}
|
|
||||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
|
||||||
bapp.Commit()
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, acc1, res1)
|
|
||||||
|
|
||||||
// Sign the tx
|
|
||||||
sequences := []int64{0}
|
|
||||||
sig := priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, sendMsg))
|
|
||||||
tx := auth.NewStdTx(sendMsg, fee, []auth.StdSignature{{
|
|
||||||
PubKey: priv1.PubKey(),
|
|
||||||
Signature: sig,
|
|
||||||
}})
|
|
||||||
|
|
||||||
// Run a Check
|
|
||||||
res := bapp.Check(tx)
|
|
||||||
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
res = bapp.Deliver(tx)
|
|
||||||
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
|
|
||||||
// Check balances
|
|
||||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
|
||||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
|
||||||
res3 := bapp.accountMapper.GetAccount(ctxDeliver, addr2)
|
|
||||||
assert.Equal(t, fmt.Sprintf("%v", res2.GetCoins()), "67foocoin")
|
|
||||||
assert.Equal(t, fmt.Sprintf("%v", res3.GetCoins()), "10foocoin")
|
|
||||||
|
|
||||||
// Delivering again should cause replay error
|
|
||||||
res = bapp.Deliver(tx)
|
|
||||||
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeInvalidSequence), sdk.ABCICodeType(res.Code), res.Log)
|
|
||||||
|
|
||||||
// bumping the txnonce number without resigning should be an auth error
|
|
||||||
tx.Signatures[0].Sequence = 1
|
|
||||||
res = bapp.Deliver(tx)
|
|
||||||
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), sdk.ABCICodeType(res.Code), res.Log)
|
|
||||||
|
|
||||||
// resigning the tx with the bumped sequence should work
|
|
||||||
sequences = []int64{1}
|
|
||||||
sig = priv1.Sign(auth.StdSignBytes(chainID, sequences, fee, tx.Msg))
|
|
||||||
tx.Signatures[0].Signature = sig
|
|
||||||
res = bapp.Deliver(tx)
|
|
||||||
assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgMine(t *testing.T) {
|
|
||||||
bapp := newDemocoinApp()
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
|
||||||
baseAcc := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: nil,
|
|
||||||
}
|
|
||||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
genesisState := map[string]interface{}{
|
|
||||||
"accounts": []*types.GenesisAccount{
|
|
||||||
types.NewGenesisAccount(acc1),
|
|
||||||
},
|
|
||||||
"cool": map[string]string{
|
|
||||||
"trend": "ice-cold",
|
|
||||||
},
|
|
||||||
"pow": map[string]uint64{
|
|
||||||
"difficulty": 1,
|
|
||||||
"count": 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Initialize the chain (nil)
|
|
||||||
vals := []abci.Validator{}
|
|
||||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
|
||||||
bapp.Commit()
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, acc1, res1)
|
|
||||||
|
|
||||||
// Mine and check for reward
|
|
||||||
mineMsg1 := pow.GenerateMsgMine(addr1, 1, 2)
|
|
||||||
SignCheckDeliver(t, bapp, mineMsg1, 0, true)
|
|
||||||
CheckBalance(t, bapp, "1pow")
|
|
||||||
// Mine again and check for reward
|
|
||||||
mineMsg2 := pow.GenerateMsgMine(addr1, 2, 3)
|
|
||||||
SignCheckDeliver(t, bapp, mineMsg2, 1, true)
|
|
||||||
CheckBalance(t, bapp, "2pow")
|
|
||||||
// Mine again - should be invalid
|
|
||||||
SignCheckDeliver(t, bapp, mineMsg2, 1, false)
|
|
||||||
CheckBalance(t, bapp, "2pow")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMsgQuiz(t *testing.T) {
|
|
||||||
bapp := newDemocoinApp()
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
// Construct some genesis bytes to reflect democoin/types/AppAccount
|
|
||||||
baseAcc := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: nil,
|
|
||||||
}
|
|
||||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
|
||||||
|
|
||||||
// Construct genesis state
|
|
||||||
genesisState := map[string]interface{}{
|
|
||||||
"accounts": []*types.GenesisAccount{
|
|
||||||
types.NewGenesisAccount(acc1),
|
|
||||||
},
|
|
||||||
"cool": map[string]string{
|
|
||||||
"trend": "ice-cold",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Initialize the chain (nil)
|
|
||||||
vals := []abci.Validator{}
|
|
||||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
|
||||||
bapp.Commit()
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, acc1, res1)
|
|
||||||
|
|
||||||
// Set the trend, submit a really cool quiz and check for reward
|
|
||||||
SignCheckDeliver(t, bapp, setTrendMsg1, 0, true)
|
|
||||||
SignCheckDeliver(t, bapp, quizMsg1, 1, true)
|
|
||||||
CheckBalance(t, bapp, "69icecold")
|
|
||||||
SignCheckDeliver(t, bapp, quizMsg2, 2, false) // result without reward
|
|
||||||
CheckBalance(t, bapp, "69icecold")
|
|
||||||
SignCheckDeliver(t, bapp, quizMsg1, 3, true)
|
|
||||||
CheckBalance(t, bapp, "138icecold")
|
|
||||||
SignCheckDeliver(t, bapp, setTrendMsg2, 4, true) // reset the trend
|
|
||||||
SignCheckDeliver(t, bapp, quizMsg1, 5, false) // the same answer will nolonger do!
|
|
||||||
CheckBalance(t, bapp, "138icecold")
|
|
||||||
SignCheckDeliver(t, bapp, quizMsg2, 6, true) // earlier answer now relavent again
|
|
||||||
CheckBalance(t, bapp, "69badvibesonly,138icecold")
|
|
||||||
SignCheckDeliver(t, bapp, setTrendMsg3, 7, false) // expect to fail to set the trend to something which is not cool
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHandler(t *testing.T) {
|
|
||||||
bapp := newDemocoinApp()
|
|
||||||
|
|
||||||
sourceChain := "source-chain"
|
|
||||||
destChain := "dest-chain"
|
|
||||||
|
|
||||||
vals := []abci.Validator{}
|
|
||||||
baseAcc := auth.BaseAccount{
|
|
||||||
Address: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
}
|
|
||||||
acc1 := &types.AppAccount{baseAcc, "foobart"}
|
|
||||||
genesisState := map[string]interface{}{
|
|
||||||
"accounts": []*types.GenesisAccount{
|
|
||||||
types.NewGenesisAccount(acc1),
|
|
||||||
},
|
|
||||||
"cool": map[string]string{
|
|
||||||
"trend": "ice-cold",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
|
||||||
require.Nil(t, err)
|
|
||||||
bapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
|
||||||
bapp.Commit()
|
|
||||||
|
|
||||||
// A checkTx context (true)
|
|
||||||
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
|
||||||
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
|
||||||
assert.Equal(t, acc1, res1)
|
|
||||||
|
|
||||||
packet := ibc.IBCPacket{
|
|
||||||
SrcAddr: addr1,
|
|
||||||
DestAddr: addr1,
|
|
||||||
Coins: coins,
|
|
||||||
SrcChain: sourceChain,
|
|
||||||
DestChain: destChain,
|
|
||||||
}
|
|
||||||
|
|
||||||
transferMsg := ibc.IBCTransferMsg{
|
|
||||||
IBCPacket: packet,
|
|
||||||
}
|
|
||||||
|
|
||||||
receiveMsg := ibc.IBCReceiveMsg{
|
|
||||||
IBCPacket: packet,
|
|
||||||
Relayer: addr1,
|
|
||||||
Sequence: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
SignCheckDeliver(t, bapp, transferMsg, 0, true)
|
|
||||||
CheckBalance(t, bapp, "")
|
|
||||||
SignCheckDeliver(t, bapp, transferMsg, 1, false)
|
|
||||||
SignCheckDeliver(t, bapp, receiveMsg, 2, true)
|
|
||||||
CheckBalance(t, bapp, "10foocoin")
|
|
||||||
SignCheckDeliver(t, bapp, receiveMsg, 3, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO describe the use of this function
|
|
||||||
func SignCheckDeliver(t *testing.T, bapp *DemocoinApp, msg sdk.Msg, seq int64, expPass bool) {
|
|
||||||
|
|
||||||
// Sign the tx
|
|
||||||
tx := auth.NewStdTx(msg, fee, []auth.StdSignature{{
|
|
||||||
PubKey: priv1.PubKey(),
|
|
||||||
Signature: priv1.Sign(auth.StdSignBytes(chainID, []int64{seq}, fee, msg)),
|
|
||||||
Sequence: seq,
|
|
||||||
}})
|
|
||||||
|
|
||||||
// Run a Check
|
|
||||||
res := bapp.Check(tx)
|
|
||||||
if expPass {
|
|
||||||
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
} else {
|
|
||||||
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simulate a Block
|
|
||||||
bapp.BeginBlock(abci.RequestBeginBlock{})
|
|
||||||
res = bapp.Deliver(tx)
|
|
||||||
if expPass {
|
|
||||||
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
} else {
|
|
||||||
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
|
|
||||||
}
|
|
||||||
bapp.EndBlock(abci.RequestEndBlock{})
|
|
||||||
//bapp.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckBalance(t *testing.T, bapp *DemocoinApp, balExpected string) {
|
|
||||||
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
|
||||||
res2 := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
|
||||||
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
"github.com/tendermint/tmlibs/cli"
|
"github.com/tendermint/tmlibs/cli"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
@ -46,9 +47,9 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
|
||||||
return app.NewDemocoinApp(logger, db)
|
return app.NewDemocoinApp(logger, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportAppState(logger log.Logger, db dbm.DB) (json.RawMessage, error) {
|
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
dapp := app.NewDemocoinApp(logger, db)
|
dapp := app.NewDemocoinApp(logger, db)
|
||||||
return dapp.ExportAppStateJSON()
|
return dapp.ExportAppStateAndValidators()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -63,7 +64,7 @@ func main() {
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
||||||
server.ConstructAppCreator(newApp, "democoin"),
|
server.ConstructAppCreator(newApp, "democoin"),
|
||||||
server.ConstructAppExporter(exportAppState, "democoin"))
|
server.ConstructAppExporter(exportAppStateAndTMValidators, "democoin"))
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
rootDir := os.ExpandEnv("$HOME/.democoind")
|
rootDir := os.ExpandEnv("$HOME/.democoind")
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
package cool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth/mock"
|
||||||
|
bank "github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
priv1 = crypto.GenPrivKeyEd25519()
|
||||||
|
addr1 = priv1.PubKey().Address()
|
||||||
|
|
||||||
|
quizMsg1 = MsgQuiz{
|
||||||
|
Sender: addr1,
|
||||||
|
CoolAnswer: "icecold",
|
||||||
|
}
|
||||||
|
|
||||||
|
quizMsg2 = MsgQuiz{
|
||||||
|
Sender: addr1,
|
||||||
|
CoolAnswer: "badvibesonly",
|
||||||
|
}
|
||||||
|
|
||||||
|
setTrendMsg1 = MsgSetTrend{
|
||||||
|
Sender: addr1,
|
||||||
|
Cool: "icecold",
|
||||||
|
}
|
||||||
|
|
||||||
|
setTrendMsg2 = MsgSetTrend{
|
||||||
|
Sender: addr1,
|
||||||
|
Cool: "badvibesonly",
|
||||||
|
}
|
||||||
|
|
||||||
|
setTrendMsg3 = MsgSetTrend{
|
||||||
|
Sender: addr1,
|
||||||
|
Cool: "warmandkind",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// initialize the mock application for this module
|
||||||
|
func getMockApp(t *testing.T) *mock.App {
|
||||||
|
mapp := mock.NewApp()
|
||||||
|
|
||||||
|
RegisterWire(mapp.Cdc)
|
||||||
|
keyCool := sdk.NewKVStoreKey("cool")
|
||||||
|
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
|
||||||
|
keeper := NewKeeper(keyCool, coinKeeper, mapp.RegisterCodespace(DefaultCodespace))
|
||||||
|
mapp.Router().AddRoute("cool", NewHandler(keeper))
|
||||||
|
|
||||||
|
mapp.SetInitChainer(getInitChainer(mapp, keeper, "ice-cold"))
|
||||||
|
|
||||||
|
mapp.CompleteSetup(t, []*sdk.KVStoreKey{keyCool})
|
||||||
|
return mapp
|
||||||
|
}
|
||||||
|
|
||||||
|
// overwrite the mock init chainer
|
||||||
|
func getInitChainer(mapp *mock.App, keeper Keeper, newTrend string) sdk.InitChainer {
|
||||||
|
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||||
|
mapp.InitChainer(ctx, req)
|
||||||
|
keeper.setTrend(ctx, newTrend)
|
||||||
|
|
||||||
|
return abci.ResponseInitChain{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMsgQuiz(t *testing.T) {
|
||||||
|
mapp := getMockApp(t)
|
||||||
|
|
||||||
|
// Construct genesis state
|
||||||
|
acc1 := &auth.BaseAccount{
|
||||||
|
Address: addr1,
|
||||||
|
Coins: nil,
|
||||||
|
}
|
||||||
|
accs := []auth.Account{acc1}
|
||||||
|
|
||||||
|
// Initialize the chain (nil)
|
||||||
|
mock.SetGenesis(mapp, accs)
|
||||||
|
|
||||||
|
// A checkTx context (true)
|
||||||
|
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
|
||||||
|
res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1)
|
||||||
|
assert.Equal(t, acc1, res1)
|
||||||
|
|
||||||
|
// Set the trend, submit a really cool quiz and check for reward
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, setTrendMsg1, []int64{0}, []int64{0}, true, priv1)
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg1, []int64{0}, []int64{1}, true, priv1)
|
||||||
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", 69}})
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg2, []int64{0}, []int64{2}, false, priv1) // result without reward
|
||||||
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", 69}})
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg1, []int64{0}, []int64{3}, true, priv1)
|
||||||
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", 138}})
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, setTrendMsg2, []int64{0}, []int64{4}, true, priv1) // reset the trend
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg1, []int64{0}, []int64{5}, false, priv1) // the same answer will nolonger do!
|
||||||
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", 138}})
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, quizMsg2, []int64{0}, []int64{6}, true, priv1) // earlier answer now relavent again
|
||||||
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"badvibesonly", 69}, {"icecold", 138}})
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, setTrendMsg3, []int64{0}, []int64{7}, false, priv1) // expect to fail to set the trend to something which is not cool
|
||||||
|
}
|
|
@ -16,5 +16,5 @@ const (
|
||||||
|
|
||||||
// ErrIncorrectCoolAnswer - Error returned upon an incorrect guess
|
// ErrIncorrectCoolAnswer - Error returned upon an incorrect guess
|
||||||
func ErrIncorrectCoolAnswer(codespace sdk.CodespaceType, answer string) sdk.Error {
|
func ErrIncorrectCoolAnswer(codespace sdk.CodespaceType, answer string) sdk.Error {
|
||||||
return sdk.NewError(codespace, CodeIncorrectCoolAnswer, fmt.Sprintf("Incorrect cool answer: %v", answer))
|
return sdk.NewError(codespace, CodeIncorrectCoolAnswer, fmt.Sprintf("incorrect cool answer: %v", answer))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
package pow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth/mock"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
priv1 = crypto.GenPrivKeyEd25519()
|
||||||
|
addr1 = priv1.PubKey().Address()
|
||||||
|
)
|
||||||
|
|
||||||
|
// initialize the mock application for this module
|
||||||
|
func getMockApp(t *testing.T) *mock.App {
|
||||||
|
mapp := mock.NewApp()
|
||||||
|
|
||||||
|
RegisterWire(mapp.Cdc)
|
||||||
|
keyPOW := sdk.NewKVStoreKey("pow")
|
||||||
|
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
|
||||||
|
config := Config{"pow", 1}
|
||||||
|
keeper := NewKeeper(keyPOW, config, coinKeeper, mapp.RegisterCodespace(DefaultCodespace))
|
||||||
|
mapp.Router().AddRoute("pow", keeper.Handler)
|
||||||
|
|
||||||
|
mapp.SetInitChainer(getInitChainer(mapp, keeper))
|
||||||
|
|
||||||
|
mapp.CompleteSetup(t, []*sdk.KVStoreKey{keyPOW})
|
||||||
|
return mapp
|
||||||
|
}
|
||||||
|
|
||||||
|
// overwrite the mock init chainer
|
||||||
|
func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer {
|
||||||
|
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||||
|
mapp.InitChainer(ctx, req)
|
||||||
|
|
||||||
|
genesis := Genesis{
|
||||||
|
Difficulty: 1,
|
||||||
|
Count: 0,
|
||||||
|
}
|
||||||
|
InitGenesis(ctx, keeper, genesis)
|
||||||
|
|
||||||
|
return abci.ResponseInitChain{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMsgMine(t *testing.T) {
|
||||||
|
mapp := getMockApp(t)
|
||||||
|
|
||||||
|
// Construct genesis state
|
||||||
|
acc1 := &auth.BaseAccount{
|
||||||
|
Address: addr1,
|
||||||
|
Coins: nil,
|
||||||
|
}
|
||||||
|
accs := []auth.Account{acc1}
|
||||||
|
|
||||||
|
// Initialize the chain (nil)
|
||||||
|
mock.SetGenesis(mapp, accs)
|
||||||
|
|
||||||
|
// A checkTx context (true)
|
||||||
|
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
|
||||||
|
res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1)
|
||||||
|
assert.Equal(t, acc1, res1)
|
||||||
|
|
||||||
|
// Mine and check for reward
|
||||||
|
mineMsg1 := GenerateMsgMine(addr1, 1, 2)
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, mineMsg1, []int64{0}, []int64{0}, true, priv1)
|
||||||
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", 1}})
|
||||||
|
// Mine again and check for reward
|
||||||
|
mineMsg2 := GenerateMsgMine(addr1, 2, 3)
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, mineMsg2, []int64{0}, []int64{1}, true, priv1)
|
||||||
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", 2}})
|
||||||
|
// Mine again - should be invalid
|
||||||
|
mock.SignCheckDeliver(t, mapp.BaseApp, mineMsg2, []int64{0}, []int64{1}, false, priv1)
|
||||||
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", 2}})
|
||||||
|
}
|
|
@ -23,21 +23,21 @@ const (
|
||||||
func codeToDefaultMsg(code CodeType) string {
|
func codeToDefaultMsg(code CodeType) string {
|
||||||
switch code {
|
switch code {
|
||||||
case CodeInvalidDifficulty:
|
case CodeInvalidDifficulty:
|
||||||
return "Insuffient difficulty"
|
return "insuffient difficulty"
|
||||||
case CodeNonexistentDifficulty:
|
case CodeNonexistentDifficulty:
|
||||||
return "Nonexistent difficulty"
|
return "nonexistent difficulty"
|
||||||
case CodeNonexistentReward:
|
case CodeNonexistentReward:
|
||||||
return "Nonexistent reward"
|
return "nonexistent reward"
|
||||||
case CodeNonexistentCount:
|
case CodeNonexistentCount:
|
||||||
return "Nonexistent count"
|
return "nonexistent count"
|
||||||
case CodeInvalidProof:
|
case CodeInvalidProof:
|
||||||
return "Invalid proof"
|
return "invalid proof"
|
||||||
case CodeNotBelowTarget:
|
case CodeNotBelowTarget:
|
||||||
return "Not below target"
|
return "not below target"
|
||||||
case CodeInvalidCount:
|
case CodeInvalidCount:
|
||||||
return "Invalid count"
|
return "invalid count"
|
||||||
case CodeUnknownRequest:
|
case CodeUnknownRequest:
|
||||||
return "Unknown request"
|
return "unknown request"
|
||||||
default:
|
default:
|
||||||
return sdk.CodeToDefaultMsg(code)
|
return sdk.CodeToDefaultMsg(code)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the ABCI server
|
// Start the ABCI server
|
||||||
srv, err := server.NewServer("0.0.0.0:46658", "socket", baseApp)
|
srv, err := server.NewServer("0.0.0.0:26658", "socket", baseApp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
- name: Gather status
|
- name: Gather status
|
||||||
uri:
|
uri:
|
||||||
body_format: json
|
body_format: json
|
||||||
url: "http://{{inventory_hostname}}:46657/status"
|
url: "http://{{inventory_hostname}}:26657/status"
|
||||||
register: status
|
register: status
|
||||||
|
|
||||||
- name: Print status
|
- name: Print status
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
)
|
)
|
||||||
|
@ -13,8 +14,8 @@ import (
|
||||||
// and other flags (?) to start
|
// and other flags (?) to start
|
||||||
type AppCreator func(string, log.Logger) (abci.Application, error)
|
type AppCreator func(string, log.Logger) (abci.Application, error)
|
||||||
|
|
||||||
// AppExporter dumps all app state to JSON-serializable structure
|
// AppExporter dumps all app state to JSON-serializable structure and returns the current validator set
|
||||||
type AppExporter func(home string, log log.Logger) (json.RawMessage, error)
|
type AppExporter func(home string, log log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error)
|
||||||
|
|
||||||
// ConstructAppCreator returns an application generation function
|
// ConstructAppCreator returns an application generation function
|
||||||
func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator {
|
func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name string) AppCreator {
|
||||||
|
@ -30,12 +31,12 @@ func ConstructAppCreator(appFn func(log.Logger, dbm.DB) abci.Application, name s
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConstructAppExporter returns an application export function
|
// ConstructAppExporter returns an application export function
|
||||||
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, error), name string) AppExporter {
|
func ConstructAppExporter(appFn func(log.Logger, dbm.DB) (json.RawMessage, []tmtypes.GenesisValidator, error), name string) AppExporter {
|
||||||
return func(rootDir string, logger log.Logger) (json.RawMessage, error) {
|
return func(rootDir string, logger log.Logger) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
dataDir := filepath.Join(rootDir, "data")
|
dataDir := filepath.Join(rootDir, "data")
|
||||||
db, err := dbm.NewGoLevelDB(name, dataDir)
|
db, err := dbm.NewGoLevelDB(name, dataDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return appFn(logger, db)
|
return appFn(logger, db)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,15 +18,16 @@ func ExportCmd(ctx *Context, cdc *wire.Codec, appExporter AppExporter) *cobra.Co
|
||||||
Short: "Export state to JSON",
|
Short: "Export state to JSON",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
home := viper.GetString("home")
|
home := viper.GetString("home")
|
||||||
appState, err := appExporter(home, ctx.Logger)
|
appState, validators, err := appExporter(home, ctx.Logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Errorf("Error exporting state: %v\n", err)
|
return errors.Errorf("error exporting state: %v\n", err)
|
||||||
}
|
}
|
||||||
doc, err := tmtypes.GenesisDocFromFile(ctx.Config.GenesisFile())
|
doc, err := tmtypes.GenesisDocFromFile(ctx.Config.GenesisFile())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
doc.AppStateJSON = appState
|
doc.AppStateJSON = appState
|
||||||
|
doc.Validators = validators
|
||||||
encoded, err := wire.MarshalJSONIndent(cdc, doc)
|
encoded, err := wire.MarshalJSONIndent(cdc, doc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
"github.com/tendermint/tendermint/p2p"
|
"github.com/tendermint/tendermint/p2p"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
pvm "github.com/tendermint/tendermint/privval"
|
||||||
tmcli "github.com/tendermint/tmlibs/cli"
|
tmcli "github.com/tendermint/tmlibs/cli"
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
|
@ -255,7 +255,7 @@ func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) (
|
||||||
if len(persistentPeers) == 0 {
|
if len(persistentPeers) == 0 {
|
||||||
comma = ""
|
comma = ""
|
||||||
}
|
}
|
||||||
persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, genTx.NodeID, genTx.IP)
|
persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/mock"
|
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
|
|
||||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
"github.com/tendermint/tendermint/node"
|
"github.com/tendermint/tendermint/node"
|
||||||
|
pvm "github.com/tendermint/tendermint/privval"
|
||||||
"github.com/tendermint/tendermint/proxy"
|
"github.com/tendermint/tendermint/proxy"
|
||||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command {
|
||||||
|
|
||||||
// basic flags for abci app
|
// basic flags for abci app
|
||||||
cmd.Flags().Bool(flagWithTendermint, true, "run abci app embedded in-process with tendermint")
|
cmd.Flags().Bool(flagWithTendermint, true, "run abci app embedded in-process with tendermint")
|
||||||
cmd.Flags().String(flagAddress, "tcp://0.0.0.0:46658", "Listen address")
|
cmd.Flags().String(flagAddress, "tcp://0.0.0.0:26658", "Listen address")
|
||||||
|
|
||||||
// AddNodeFlags adds support for all tendermint-specific command line options
|
// AddNodeFlags adds support for all tendermint-specific command line options
|
||||||
tcmd.AddNodeFlags(cmd)
|
tcmd.AddNodeFlags(cmd)
|
||||||
|
@ -55,7 +55,7 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error {
|
||||||
|
|
||||||
svr, err := server.NewServer(addr, "socket", app)
|
svr, err := server.NewServer(addr, "socket", app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Errorf("Error creating listener: %v\n", err)
|
return errors.Errorf("error creating listener: %v\n", err)
|
||||||
}
|
}
|
||||||
svr.SetLogger(ctx.Logger.With("module", "abci-server"))
|
svr.SetLogger(ctx.Logger.With("module", "abci-server"))
|
||||||
svr.Start()
|
svr.Start()
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/mock"
|
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/tendermint/abci/server"
|
"github.com/tendermint/abci/server"
|
||||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
|
@ -40,7 +40,7 @@ func TestStartStandAlone(t *testing.T) {
|
||||||
svrAddr, _, err := FreeTCPAddr()
|
svrAddr, _, err := FreeTCPAddr()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
svr, err := server.NewServer(svrAddr, "socket", app)
|
svr, err := server.NewServer(svrAddr, "socket", app)
|
||||||
require.Nil(t, err, "Error creating listener")
|
require.Nil(t, err, "error creating listener")
|
||||||
svr.SetLogger(logger.With("module", "abci-server"))
|
svr.SetLogger(logger.With("module", "abci-server"))
|
||||||
svr.Start()
|
svr.Start()
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
"github.com/tendermint/tendermint/p2p"
|
"github.com/tendermint/tendermint/p2p"
|
||||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
pvm "github.com/tendermint/tendermint/privval"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShowNodeIDCmd - ported from Tendermint, dump node ID to stdout
|
// ShowNodeIDCmd - ported from Tendermint, dump node ID to stdout
|
||||||
|
@ -72,7 +72,7 @@ func UnsafeResetAllCmd(ctx *Context) *cobra.Command {
|
||||||
Short: "Reset blockchain database, priv_validator.json file, and the logger",
|
Short: "Reset blockchain database, priv_validator.json file, and the logger",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
cfg := ctx.Config
|
cfg := ctx.Config
|
||||||
tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), ctx.Logger)
|
tcmd.ResetAll(cfg.DBDir(), cfg.P2P.AddrBookFile(), cfg.PrivValidatorFile(), ctx.Logger)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
|
||||||
id := CommitID{}
|
id := CommitID{}
|
||||||
store, err := rs.loadCommitStoreFromParams(id, storeParams)
|
store, err := rs.loadCommitStoreFromParams(id, storeParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to load rootMultiStore: %v", err)
|
return fmt.Errorf("failed to load rootMultiStore: %v", err)
|
||||||
}
|
}
|
||||||
rs.stores[key] = store
|
rs.stores[key] = store
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
|
||||||
storeParams := rs.storesParams[key]
|
storeParams := rs.storesParams[key]
|
||||||
store, err := rs.loadCommitStoreFromParams(commitID, storeParams)
|
store, err := rs.loadCommitStoreFromParams(commitID, storeParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to load rootMultiStore: %v", err)
|
return fmt.Errorf("failed to load rootMultiStore: %v", err)
|
||||||
}
|
}
|
||||||
newStores[key] = store
|
newStores[key] = store
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error {
|
||||||
// If any CommitStoreLoaders were not used, return error.
|
// If any CommitStoreLoaders were not used, return error.
|
||||||
for key := range rs.storesParams {
|
for key := range rs.storesParams {
|
||||||
if _, ok := newStores[key]; !ok {
|
if _, ok := newStores[key]; !ok {
|
||||||
return fmt.Errorf("Unused CommitStoreLoader: %v", key)
|
return fmt.Errorf("unused CommitStoreLoader: %v", key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,14 +399,14 @@ func getCommitInfo(db dbm.DB, ver int64) (commitInfo, error) {
|
||||||
cInfoKey := fmt.Sprintf(commitInfoKeyFmt, ver)
|
cInfoKey := fmt.Sprintf(commitInfoKeyFmt, ver)
|
||||||
cInfoBytes := db.Get([]byte(cInfoKey))
|
cInfoBytes := db.Get([]byte(cInfoKey))
|
||||||
if cInfoBytes == nil {
|
if cInfoBytes == nil {
|
||||||
return commitInfo{}, fmt.Errorf("Failed to get rootMultiStore: no data")
|
return commitInfo{}, fmt.Errorf("failed to get rootMultiStore: no data")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse bytes.
|
// Parse bytes.
|
||||||
var cInfo commitInfo
|
var cInfo commitInfo
|
||||||
err := cdc.UnmarshalBinary(cInfoBytes, &cInfo)
|
err := cdc.UnmarshalBinary(cInfoBytes, &cInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return commitInfo{}, fmt.Errorf("Failed to get rootMultiStore: %v", err)
|
return commitInfo{}, fmt.Errorf("failed to get rootMultiStore: %v", err)
|
||||||
}
|
}
|
||||||
return cInfo, nil
|
return cInfo, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,65 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
amino "github.com/tendermint/go-amino"
|
amino "github.com/tendermint/go-amino"
|
||||||
|
tmclient "github.com/tendermint/tendermint/rpc/client"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Uses localhost
|
// Wait for the next tendermint block from the Tendermint RPC
|
||||||
func WaitForHeight(height int64, port string) {
|
// on localhost
|
||||||
|
func WaitForNextHeightTM(port string) {
|
||||||
|
url := fmt.Sprintf("http://localhost:%v", port)
|
||||||
|
cl := tmclient.NewHTTP(url, "/websocket")
|
||||||
|
resBlock, err := cl.Block(nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
waitForHeightTM(resBlock.Block.Height+1, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the given height from the Tendermint RPC
|
||||||
|
// on localhost
|
||||||
|
func WaitForHeightTM(height int64, port string) {
|
||||||
|
url := fmt.Sprintf("http://localhost:%v", port)
|
||||||
|
waitForHeightTM(height, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForHeightTM(height int64, url string) {
|
||||||
|
cl := tmclient.NewHTTP(url, "/websocket")
|
||||||
for {
|
for {
|
||||||
|
// get url, try a few times
|
||||||
|
var resBlock *ctypes.ResultBlock
|
||||||
|
var err error
|
||||||
|
INNER:
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
resBlock, err = cl.Block(nil)
|
||||||
|
if err == nil {
|
||||||
|
break INNER
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 200)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
|
if resBlock.Block != nil &&
|
||||||
|
resBlock.Block.Height >= height {
|
||||||
|
fmt.Println("HEIGHT", resBlock.Block.Height)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for height from the LCD API on localhost
|
||||||
|
func WaitForHeight(height int64, port string) {
|
||||||
|
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
|
||||||
|
waitForHeight(height, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForHeight(height int64, url string) {
|
||||||
|
for {
|
||||||
// get url, try a few times
|
// get url, try a few times
|
||||||
var res *http.Response
|
var res *http.Response
|
||||||
var err error
|
var err error
|
||||||
|
@ -25,7 +74,7 @@ func WaitForHeight(height int64, port string) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Millisecond * 200)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -45,7 +94,8 @@ func WaitForHeight(height int64, port string) {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if resultBlock.Block.Height >= height {
|
if resultBlock.Block != nil &&
|
||||||
|
resultBlock.Block.Height >= height {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
|
|
@ -26,21 +26,57 @@ func Bech32ifyAcc(addr Address) (string, error) {
|
||||||
return bech32.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes())
|
return bech32.ConvertAndEncode(Bech32PrefixAccAddr, addr.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustBech32ifyAcc panics on bech32-encoding failure
|
||||||
|
func MustBech32ifyAcc(addr Address) string {
|
||||||
|
enc, err := Bech32ifyAcc(addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return enc
|
||||||
|
}
|
||||||
|
|
||||||
// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string
|
// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string
|
||||||
func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
|
func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
|
||||||
return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
|
return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustBech32ifyAccPub panics on bech32-encoding failure
|
||||||
|
func MustBech32ifyAccPub(pub crypto.PubKey) string {
|
||||||
|
enc, err := Bech32ifyAccPub(pub)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return enc
|
||||||
|
}
|
||||||
|
|
||||||
// Bech32ifyVal returns the bech32 encoded string for a validator address
|
// Bech32ifyVal returns the bech32 encoded string for a validator address
|
||||||
func bech32ifyVal(addr Address) (string, error) {
|
func Bech32ifyVal(addr Address) (string, error) {
|
||||||
return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes())
|
return bech32.ConvertAndEncode(Bech32PrefixValAddr, addr.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustBech32ifyVal panics on bech32-encoding failure
|
||||||
|
func MustBech32ifyVal(addr Address) string {
|
||||||
|
enc, err := Bech32ifyVal(addr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return enc
|
||||||
|
}
|
||||||
|
|
||||||
// Bech32ifyValPub returns the bech32 encoded string for a validator pubkey
|
// Bech32ifyValPub returns the bech32 encoded string for a validator pubkey
|
||||||
func Bech32ifyValPub(pub crypto.PubKey) (string, error) {
|
func Bech32ifyValPub(pub crypto.PubKey) (string, error) {
|
||||||
return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
|
return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustBech32ifyValPub pancis on bech32-encoding failure
|
||||||
|
func MustBech32ifyValPub(pub crypto.PubKey) string {
|
||||||
|
enc, err := Bech32ifyValPub(pub)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return enc
|
||||||
|
}
|
||||||
|
|
||||||
// create an Address from a string
|
// create an Address from a string
|
||||||
func GetAccAddressHex(address string) (addr Address, err error) {
|
func GetAccAddressHex(address string) (addr Address, err error) {
|
||||||
if len(address) == 0 {
|
if len(address) == 0 {
|
||||||
|
@ -55,13 +91,28 @@ func GetAccAddressHex(address string) (addr Address, err error) {
|
||||||
|
|
||||||
// create an Address from a string
|
// create an Address from a string
|
||||||
func GetAccAddressBech32(address string) (addr Address, err error) {
|
func GetAccAddressBech32(address string) (addr Address, err error) {
|
||||||
bz, err := getFromBech32(address, Bech32PrefixAccAddr)
|
bz, err := GetFromBech32(address, Bech32PrefixAccAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return Address(bz), nil
|
return Address(bz), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create a Pubkey from a string
|
||||||
|
func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) {
|
||||||
|
bz, err := GetFromBech32(address, Bech32PrefixAccPub)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pk, err = crypto.PubKeyFromBytes(bz)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pk, nil
|
||||||
|
}
|
||||||
|
|
||||||
// create an Address from a hex string
|
// create an Address from a hex string
|
||||||
func GetValAddressHex(address string) (addr Address, err error) {
|
func GetValAddressHex(address string) (addr Address, err error) {
|
||||||
if len(address) == 0 {
|
if len(address) == 0 {
|
||||||
|
@ -76,16 +127,16 @@ func GetValAddressHex(address string) (addr Address, err error) {
|
||||||
|
|
||||||
// create an Address from a bech32 string
|
// create an Address from a bech32 string
|
||||||
func GetValAddressBech32(address string) (addr Address, err error) {
|
func GetValAddressBech32(address string) (addr Address, err error) {
|
||||||
bz, err := getFromBech32(address, Bech32PrefixValAddr)
|
bz, err := GetFromBech32(address, Bech32PrefixValAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return Address(bz), nil
|
return Address(bz), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//Decode a validator publickey into a public key
|
// decode a validator public key into a PubKey
|
||||||
func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
|
func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
|
||||||
bz, err := getFromBech32(pubkey, Bech32PrefixValPub)
|
bz, err := GetFromBech32(pubkey, Bech32PrefixValPub)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -98,7 +149,8 @@ func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
|
||||||
return pk, nil
|
return pk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFromBech32(bech32str, prefix string) ([]byte, error) {
|
// decode a bytestring from a bech32-encoded string
|
||||||
|
func GetFromBech32(bech32str, prefix string) ([]byte, error) {
|
||||||
if len(bech32str) == 0 {
|
if len(bech32str) == 0 {
|
||||||
return nil, errors.New("must provide non-empty string")
|
return nil, errors.New("must provide non-empty string")
|
||||||
}
|
}
|
||||||
|
@ -108,7 +160,7 @@ func getFromBech32(bech32str, prefix string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if hrp != prefix {
|
if hrp != prefix {
|
||||||
return nil, fmt.Errorf("Invalid bech32 prefix. Expected %s, Got %s", prefix, hrp)
|
return nil, fmt.Errorf("invalid bech32 prefix. Expected %s, Got %s", prefix, hrp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return bz, nil
|
return bz, nil
|
||||||
|
|
|
@ -280,7 +280,7 @@ func ParseCoin(coinStr string) (coin Coin, err error) {
|
||||||
|
|
||||||
matches := reCoin.FindStringSubmatch(coinStr)
|
matches := reCoin.FindStringSubmatch(coinStr)
|
||||||
if matches == nil {
|
if matches == nil {
|
||||||
err = fmt.Errorf("Invalid coin expression: %s", coinStr)
|
err = fmt.Errorf("invalid coin expression: %s", coinStr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
denomStr, amountStr := matches[2], matches[1]
|
denomStr, amountStr := matches[2], matches[1]
|
||||||
|
@ -316,7 +316,7 @@ func ParseCoins(coinsStr string) (coins Coins, err error) {
|
||||||
|
|
||||||
// Validate coins before returning.
|
// Validate coins before returning.
|
||||||
if !coins.IsValid() {
|
if !coins.IsValid() {
|
||||||
return nil, fmt.Errorf("ParseCoins invalid: %#v", coins)
|
return nil, fmt.Errorf("parseCoins invalid: %#v", coins)
|
||||||
}
|
}
|
||||||
|
|
||||||
return coins, nil
|
return coins, nil
|
||||||
|
|
|
@ -68,31 +68,31 @@ const (
|
||||||
func CodeToDefaultMsg(code CodeType) string {
|
func CodeToDefaultMsg(code CodeType) string {
|
||||||
switch code {
|
switch code {
|
||||||
case CodeInternal:
|
case CodeInternal:
|
||||||
return "Internal error"
|
return "internal error"
|
||||||
case CodeTxDecode:
|
case CodeTxDecode:
|
||||||
return "Tx parse error"
|
return "tx parse error"
|
||||||
case CodeInvalidSequence:
|
case CodeInvalidSequence:
|
||||||
return "Invalid sequence"
|
return "invalid sequence"
|
||||||
case CodeUnauthorized:
|
case CodeUnauthorized:
|
||||||
return "Unauthorized"
|
return "unauthorized"
|
||||||
case CodeInsufficientFunds:
|
case CodeInsufficientFunds:
|
||||||
return "Insufficent funds"
|
return "insufficent funds"
|
||||||
case CodeUnknownRequest:
|
case CodeUnknownRequest:
|
||||||
return "Unknown request"
|
return "unknown request"
|
||||||
case CodeInvalidAddress:
|
case CodeInvalidAddress:
|
||||||
return "Invalid address"
|
return "invalid address"
|
||||||
case CodeInvalidPubKey:
|
case CodeInvalidPubKey:
|
||||||
return "Invalid pubkey"
|
return "invalid pubkey"
|
||||||
case CodeUnknownAddress:
|
case CodeUnknownAddress:
|
||||||
return "Unknown address"
|
return "unknown address"
|
||||||
case CodeInsufficientCoins:
|
case CodeInsufficientCoins:
|
||||||
return "Insufficient coins"
|
return "insufficient coins"
|
||||||
case CodeInvalidCoins:
|
case CodeInvalidCoins:
|
||||||
return "Invalid coins"
|
return "invalid coins"
|
||||||
case CodeOutOfGas:
|
case CodeOutOfGas:
|
||||||
return "Out of gas"
|
return "out of gas"
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("Unknown code %d", code)
|
return fmt.Sprintf("unknown code %d", code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ type sdkError struct {
|
||||||
|
|
||||||
// Implements ABCIError.
|
// Implements ABCIError.
|
||||||
func (err *sdkError) Error() string {
|
func (err *sdkError) Error() string {
|
||||||
return fmt.Sprintf("Error{%d:%d,%#v}", err.codespace, err.code, err.err)
|
return fmt.Sprintf("error{%d:%d,%#v}", err.codespace, err.code, err.err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements ABCIError.
|
// Implements ABCIError.
|
||||||
|
|
|
@ -32,6 +32,7 @@ func BondStatusToString(b BondStatus) string {
|
||||||
|
|
||||||
// validator for a delegated proof of stake system
|
// validator for a delegated proof of stake system
|
||||||
type Validator interface {
|
type Validator interface {
|
||||||
|
GetMoniker() string // moniker of the validator
|
||||||
GetStatus() BondStatus // status of the validator
|
GetStatus() BondStatus // status of the validator
|
||||||
GetOwner() Address // owner address to receive/return validators coins
|
GetOwner() Address // owner address to receive/return validators coins
|
||||||
GetPubKey() crypto.PubKey // validation pubkey
|
GetPubKey() crypto.PubKey // validation pubkey
|
||||||
|
|
|
@ -5,4 +5,5 @@ import wire "github.com/cosmos/cosmos-sdk/wire"
|
||||||
// Register the sdk message type
|
// Register the sdk message type
|
||||||
func RegisterWire(cdc *wire.Codec) {
|
func RegisterWire(cdc *wire.Codec) {
|
||||||
cdc.RegisterInterface((*Msg)(nil), nil)
|
cdc.RegisterInterface((*Msg)(nil), nil)
|
||||||
|
cdc.RegisterInterface((*Tx)(nil), nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
//nolint
|
//nolint
|
||||||
package version
|
package version
|
||||||
|
|
||||||
// when updating these,
|
|
||||||
// remember to also update examples/basecoin/tests/cli/rpc.sh
|
|
||||||
// TODO improve
|
|
||||||
|
|
||||||
const Maj = "0"
|
const Maj = "0"
|
||||||
const Min = "18"
|
const Min = "20"
|
||||||
const Fix = "0"
|
const Fix = "0"
|
||||||
|
|
||||||
const Version = "0.18.0-dev"
|
const Version = "0.20.0-dev"
|
||||||
|
|
||||||
// GitCommit set by build flags
|
// GitCommit set by build flags
|
||||||
var GitCommit = ""
|
var GitCommit = ""
|
||||||
|
|
|
@ -17,6 +17,9 @@ type Account interface {
|
||||||
GetPubKey() crypto.PubKey // can return nil.
|
GetPubKey() crypto.PubKey // can return nil.
|
||||||
SetPubKey(crypto.PubKey) error
|
SetPubKey(crypto.PubKey) error
|
||||||
|
|
||||||
|
GetAccountNumber() int64
|
||||||
|
SetAccountNumber(int64) error
|
||||||
|
|
||||||
GetSequence() int64
|
GetSequence() int64
|
||||||
SetSequence(int64) error
|
SetSequence(int64) error
|
||||||
|
|
||||||
|
@ -36,10 +39,11 @@ var _ Account = (*BaseAccount)(nil)
|
||||||
// Extend this by embedding this in your AppAccount.
|
// Extend this by embedding this in your AppAccount.
|
||||||
// See the examples/basecoin/types/account.go for an example.
|
// See the examples/basecoin/types/account.go for an example.
|
||||||
type BaseAccount struct {
|
type BaseAccount struct {
|
||||||
Address sdk.Address `json:"address"`
|
Address sdk.Address `json:"address"`
|
||||||
Coins sdk.Coins `json:"coins"`
|
Coins sdk.Coins `json:"coins"`
|
||||||
PubKey crypto.PubKey `json:"public_key"`
|
PubKey crypto.PubKey `json:"public_key"`
|
||||||
Sequence int64 `json:"sequence"`
|
AccountNumber int64 `json:"account_number"`
|
||||||
|
Sequence int64 `json:"sequence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBaseAccountWithAddress(addr sdk.Address) BaseAccount {
|
func NewBaseAccountWithAddress(addr sdk.Address) BaseAccount {
|
||||||
|
@ -84,6 +88,17 @@ func (acc *BaseAccount) SetCoins(coins sdk.Coins) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements Account
|
||||||
|
func (acc *BaseAccount) GetAccountNumber() int64 {
|
||||||
|
return acc.AccountNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Account
|
||||||
|
func (acc *BaseAccount) SetAccountNumber(accNumber int64) error {
|
||||||
|
acc.AccountNumber = accNumber
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Implements sdk.Account.
|
// Implements sdk.Account.
|
||||||
func (acc *BaseAccount) GetSequence() int64 {
|
func (acc *BaseAccount) GetSequence() int64 {
|
||||||
return acc.Sequence
|
return acc.Sequence
|
||||||
|
|
|
@ -14,7 +14,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewAnteHandler returns an AnteHandler that checks
|
// NewAnteHandler returns an AnteHandler that checks
|
||||||
// and increments sequence numbers, checks signatures,
|
// and increments sequence numbers, checks signatures & account numbers,
|
||||||
// and deducts fees from the first signer.
|
// and deducts fees from the first signer.
|
||||||
func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
||||||
|
|
||||||
|
@ -46,11 +46,15 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the sign bytes (requires all sequence numbers and the fee)
|
// Get the sign bytes (requires all account & sequence numbers and the fee)
|
||||||
sequences := make([]int64, len(signerAddrs))
|
sequences := make([]int64, len(signerAddrs))
|
||||||
for i := 0; i < len(signerAddrs); i++ {
|
for i := 0; i < len(signerAddrs); i++ {
|
||||||
sequences[i] = sigs[i].Sequence
|
sequences[i] = sigs[i].Sequence
|
||||||
}
|
}
|
||||||
|
accNums := make([]int64, len(signerAddrs))
|
||||||
|
for i := 0; i < len(signerAddrs); i++ {
|
||||||
|
accNums[i] = sigs[i].AccountNumber
|
||||||
|
}
|
||||||
fee := stdTx.Fee
|
fee := stdTx.Fee
|
||||||
chainID := ctx.ChainID()
|
chainID := ctx.ChainID()
|
||||||
// XXX: major hack; need to get ChainID
|
// XXX: major hack; need to get ChainID
|
||||||
|
@ -58,7 +62,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
||||||
if chainID == "" {
|
if chainID == "" {
|
||||||
chainID = viper.GetString("chain-id")
|
chainID = viper.GetString("chain-id")
|
||||||
}
|
}
|
||||||
signBytes := StdSignBytes(ctx.ChainID(), sequences, fee, msg)
|
signBytes := StdSignBytes(ctx.ChainID(), accNums, sequences, fee, msg)
|
||||||
|
|
||||||
// Check sig and nonce and collect signer accounts.
|
// Check sig and nonce and collect signer accounts.
|
||||||
var signerAccs = make([]Account, len(signerAddrs))
|
var signerAccs = make([]Account, len(signerAddrs))
|
||||||
|
@ -117,6 +121,13 @@ func processSig(
|
||||||
return nil, sdk.ErrUnknownAddress(addr.String()).Result()
|
return nil, sdk.ErrUnknownAddress(addr.String()).Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check account number.
|
||||||
|
accnum := acc.GetAccountNumber()
|
||||||
|
if accnum != sig.AccountNumber {
|
||||||
|
return nil, sdk.ErrInvalidSequence(
|
||||||
|
fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result()
|
||||||
|
}
|
||||||
|
|
||||||
// Check and increment sequence number.
|
// Check and increment sequence number.
|
||||||
seq := acc.GetSequence()
|
seq := acc.GetSequence()
|
||||||
if seq != sig.Sequence {
|
if seq != sig.Sequence {
|
||||||
|
|
|
@ -52,15 +52,15 @@ func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context,
|
||||||
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code)
|
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee StdFee) sdk.Tx {
|
func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee) sdk.Tx {
|
||||||
signBytes := StdSignBytes(ctx.ChainID(), seqs, fee, msg)
|
signBytes := StdSignBytes(ctx.ChainID(), accNums, seqs, fee, msg)
|
||||||
return newTestTxWithSignBytes(msg, privs, seqs, fee, signBytes)
|
return newTestTxWithSignBytes(msg, privs, accNums, seqs, fee, signBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee StdFee, signBytes []byte) sdk.Tx {
|
func newTestTxWithSignBytes(msg sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee, signBytes []byte) sdk.Tx {
|
||||||
sigs := make([]StdSignature, len(privs))
|
sigs := make([]StdSignature, len(privs))
|
||||||
for i, priv := range privs {
|
for i, priv := range privs {
|
||||||
sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), Sequence: seqs[i]}
|
sigs[i] = StdSignature{PubKey: priv.PubKey(), Signature: priv.Sign(signBytes), AccountNumber: accNums[i], Sequence: seqs[i]}
|
||||||
}
|
}
|
||||||
tx := NewStdTx(msg, fee, sigs)
|
tx := NewStdTx(msg, fee, sigs)
|
||||||
return tx
|
return tx
|
||||||
|
@ -87,18 +87,18 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
||||||
fee := newStdFee()
|
fee := newStdFee()
|
||||||
|
|
||||||
// test no signatures
|
// test no signatures
|
||||||
privs, seqs := []crypto.PrivKey{}, []int64{}
|
privs, accNums, seqs := []crypto.PrivKey{}, []int64{}, []int64{}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accNums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||||
|
|
||||||
// test num sigs dont match GetSigners
|
// test num sigs dont match GetSigners
|
||||||
privs, seqs = []crypto.PrivKey{priv1}, []int64{0}
|
privs, accNums, seqs = []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accNums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||||
|
|
||||||
// test an unrecognized account
|
// test an unrecognized account
|
||||||
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 0}
|
privs, accNums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{0, 0}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accNums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnknownAddress)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnknownAddress)
|
||||||
|
|
||||||
// save the first account, but second is still unrecognized
|
// save the first account, but second is still unrecognized
|
||||||
|
@ -108,6 +108,61 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnknownAddress)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnknownAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test logic around account number checking with one signer and many signers.
|
||||||
|
func TestAnteHandlerAccountNumbers(t *testing.T) {
|
||||||
|
// setup
|
||||||
|
ms, capKey, capKey2 := setupMultiStore()
|
||||||
|
cdc := wire.NewCodec()
|
||||||
|
RegisterBaseAccount(cdc)
|
||||||
|
mapper := NewAccountMapper(cdc, capKey, &BaseAccount{})
|
||||||
|
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||||
|
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||||
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, nil, log.NewNopLogger())
|
||||||
|
|
||||||
|
// keys and addresses
|
||||||
|
priv1, addr1 := privAndAddr()
|
||||||
|
priv2, addr2 := privAndAddr()
|
||||||
|
|
||||||
|
// set the accounts
|
||||||
|
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||||
|
acc1.SetCoins(newCoins())
|
||||||
|
mapper.SetAccount(ctx, acc1)
|
||||||
|
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||||
|
acc2.SetCoins(newCoins())
|
||||||
|
mapper.SetAccount(ctx, acc2)
|
||||||
|
|
||||||
|
// msg and signatures
|
||||||
|
var tx sdk.Tx
|
||||||
|
msg := newTestMsg(addr1)
|
||||||
|
fee := newStdFee()
|
||||||
|
|
||||||
|
// test good tx from one signer
|
||||||
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
||||||
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
|
// new tx from wrong account number
|
||||||
|
seqs = []int64{1}
|
||||||
|
tx = newTestTx(ctx, msg, privs, []int64{1}, seqs, fee)
|
||||||
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
|
// from correct account number
|
||||||
|
seqs = []int64{1}
|
||||||
|
tx = newTestTx(ctx, msg, privs, []int64{0}, seqs, fee)
|
||||||
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
|
// new tx with another signer and incorrect account numbers
|
||||||
|
msg = newTestMsg(addr1, addr2)
|
||||||
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{1, 0}, []int64{2, 0}
|
||||||
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
|
// correct account numbers
|
||||||
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{2, 0}
|
||||||
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
}
|
||||||
|
|
||||||
// Test logic around sequence checking with one signer and many signers.
|
// Test logic around sequence checking with one signer and many signers.
|
||||||
func TestAnteHandlerSequences(t *testing.T) {
|
func TestAnteHandlerSequences(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
|
@ -137,8 +192,8 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||||
fee := newStdFee()
|
fee := newStdFee()
|
||||||
|
|
||||||
// test good tx from one signer
|
// test good tx from one signer
|
||||||
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx)
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
// test sending it again fails (replay protection)
|
// test sending it again fails (replay protection)
|
||||||
|
@ -146,13 +201,13 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||||
|
|
||||||
// fix sequence, should pass
|
// fix sequence, should pass
|
||||||
seqs = []int64{1}
|
seqs = []int64{1}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx)
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
// new tx with another signer and correct sequences
|
// new tx with another signer and correct sequences
|
||||||
msg = newTestMsg(addr1, addr2)
|
msg = newTestMsg(addr1, addr2)
|
||||||
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{2, 0}
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{2, 0}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx)
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
// replay fails
|
// replay fails
|
||||||
|
@ -160,18 +215,18 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||||
|
|
||||||
// tx from just second signer with incorrect sequence fails
|
// tx from just second signer with incorrect sequence fails
|
||||||
msg = newTestMsg(addr2)
|
msg = newTestMsg(addr2)
|
||||||
privs, seqs = []crypto.PrivKey{priv2}, []int64{0}
|
privs, accnums, seqs = []crypto.PrivKey{priv2}, []int64{1}, []int64{0}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
// fix the sequence and it passes
|
// fix the sequence and it passes
|
||||||
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{1}, fee)
|
tx = newTestTx(ctx, msg, []crypto.PrivKey{priv2}, []int64{1}, []int64{1}, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx)
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
// another tx from both of them that passes
|
// another tx from both of them that passes
|
||||||
msg = newTestMsg(addr1, addr2)
|
msg = newTestMsg(addr1, addr2)
|
||||||
privs, seqs = []crypto.PrivKey{priv1, priv2}, []int64{3, 2}
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{3, 2}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx)
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,13 +251,13 @@ func TestAnteHandlerFees(t *testing.T) {
|
||||||
// msg and signatures
|
// msg and signatures
|
||||||
var tx sdk.Tx
|
var tx sdk.Tx
|
||||||
msg := newTestMsg(addr1)
|
msg := newTestMsg(addr1)
|
||||||
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
||||||
fee := NewStdFee(100,
|
fee := NewStdFee(100,
|
||||||
sdk.Coin{"atom", 150},
|
sdk.Coin{"atom", 150},
|
||||||
)
|
)
|
||||||
|
|
||||||
// signer does not have enough funds to pay the fee
|
// signer does not have enough funds to pay the fee
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInsufficientFunds)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInsufficientFunds)
|
||||||
|
|
||||||
acc1.SetCoins(sdk.Coins{{"atom", 149}})
|
acc1.SetCoins(sdk.Coins{{"atom", 149}})
|
||||||
|
@ -249,8 +304,8 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||||
fee3.Amount[0].Amount += 100
|
fee3.Amount[0].Amount += 100
|
||||||
|
|
||||||
// test good tx and signBytes
|
// test good tx and signBytes
|
||||||
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx)
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
chainID := ctx.ChainID()
|
chainID := ctx.ChainID()
|
||||||
|
@ -259,37 +314,39 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
chainID string
|
chainID string
|
||||||
|
accnums []int64
|
||||||
seqs []int64
|
seqs []int64
|
||||||
fee StdFee
|
fee StdFee
|
||||||
msg sdk.Msg
|
msg sdk.Msg
|
||||||
code sdk.CodeType
|
code sdk.CodeType
|
||||||
}{
|
}{
|
||||||
{chainID2, []int64{1}, fee, msg, codeUnauth}, // test wrong chain_id
|
{chainID2, []int64{0}, []int64{1}, fee, msg, codeUnauth}, // test wrong chain_id
|
||||||
{chainID, []int64{2}, fee, msg, codeUnauth}, // test wrong seqs
|
{chainID, []int64{0}, []int64{2}, fee, msg, codeUnauth}, // test wrong seqs
|
||||||
{chainID, []int64{1, 2}, fee, msg, codeUnauth}, // test wrong seqs
|
{chainID, []int64{0}, []int64{1, 2}, fee, msg, codeUnauth}, // test wrong seqs
|
||||||
{chainID, []int64{1}, fee, newTestMsg(addr2), codeUnauth}, // test wrong msg
|
{chainID, []int64{1}, []int64{1}, fee, msg, codeUnauth}, // test wrong accnum
|
||||||
{chainID, []int64{1}, fee2, newTestMsg(addr2), codeUnauth}, // test wrong fee
|
{chainID, []int64{0}, []int64{1}, fee, newTestMsg(addr2), codeUnauth}, // test wrong msg
|
||||||
{chainID, []int64{1}, fee3, newTestMsg(addr2), codeUnauth}, // test wrong fee
|
{chainID, []int64{0}, []int64{1}, fee2, msg, codeUnauth}, // test wrong fee
|
||||||
|
{chainID, []int64{0}, []int64{1}, fee3, msg, codeUnauth}, // test wrong fee
|
||||||
}
|
}
|
||||||
|
|
||||||
privs, seqs = []crypto.PrivKey{priv1}, []int64{1}
|
privs, seqs = []crypto.PrivKey{priv1}, []int64{1}
|
||||||
for _, cs := range cases {
|
for _, cs := range cases {
|
||||||
tx := newTestTxWithSignBytes(
|
tx := newTestTxWithSignBytes(
|
||||||
msg, privs, seqs, fee,
|
msg, privs, accnums, seqs, fee,
|
||||||
StdSignBytes(cs.chainID, cs.seqs, cs.fee, cs.msg),
|
StdSignBytes(cs.chainID, cs.accnums, cs.seqs, cs.fee, cs.msg),
|
||||||
)
|
)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, cs.code)
|
checkInvalidTx(t, anteHandler, ctx, tx, cs.code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test wrong signer if public key exist
|
// test wrong signer if public key exist
|
||||||
privs, seqs = []crypto.PrivKey{priv2}, []int64{1}
|
privs, accnums, seqs = []crypto.PrivKey{priv2}, []int64{0}, []int64{1}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeUnauthorized)
|
||||||
|
|
||||||
// test wrong signer if public doesn't exist
|
// test wrong signer if public doesn't exist
|
||||||
msg = newTestMsg(addr2)
|
msg = newTestMsg(addr2)
|
||||||
privs, seqs = []crypto.PrivKey{priv1}, []int64{0}
|
privs, accnums, seqs = []crypto.PrivKey{priv1}, []int64{1}, []int64{0}
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -320,9 +377,9 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||||
|
|
||||||
// test good tx and set public key
|
// test good tx and set public key
|
||||||
msg := newTestMsg(addr1)
|
msg := newTestMsg(addr1)
|
||||||
privs, seqs := []crypto.PrivKey{priv1}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
||||||
fee := newStdFee()
|
fee := newStdFee()
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx)
|
checkValidTx(t, anteHandler, ctx, tx)
|
||||||
|
|
||||||
acc1 = mapper.GetAccount(ctx, addr1)
|
acc1 = mapper.GetAccount(ctx, addr1)
|
||||||
|
@ -330,7 +387,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||||
|
|
||||||
// test public key not found
|
// test public key not found
|
||||||
msg = newTestMsg(addr2)
|
msg = newTestMsg(addr2)
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, []int64{1}, seqs, fee)
|
||||||
sigs := tx.(StdTx).GetSignatures()
|
sigs := tx.(StdTx).GetSignatures()
|
||||||
sigs[0].PubKey = nil
|
sigs[0].PubKey = nil
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
||||||
|
@ -339,7 +396,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||||
assert.Nil(t, acc2.GetPubKey())
|
assert.Nil(t, acc2.GetPubKey())
|
||||||
|
|
||||||
// test invalid signature and public key
|
// test invalid signature and public key
|
||||||
tx = newTestTx(ctx, msg, privs, seqs, fee)
|
tx = newTestTx(ctx, msg, privs, []int64{1}, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
checkInvalidTx(t, anteHandler, ctx, tx, sdk.CodeInvalidPubKey)
|
||||||
|
|
||||||
acc2 = mapper.GetAccount(ctx, addr2)
|
acc2 = mapper.GetAccount(ctx, addr2)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue