commit
8550968c61
|
@ -137,6 +137,24 @@ jobs:
|
|||
export PATH="$GOBIN:$PATH"
|
||||
make test_sim_gaia_fast
|
||||
|
||||
test_sim_gaia_import_export:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/workspace
|
||||
- checkout
|
||||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make get_vendor_deps
|
||||
- run:
|
||||
name: Test Gaia import/export simulation
|
||||
command: |
|
||||
export PATH="$GOBIN:$PATH"
|
||||
make test_sim_gaia_import_export
|
||||
|
||||
test_sim_gaia_multi_seed:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
|
@ -259,6 +277,9 @@ workflows:
|
|||
- test_sim_gaia_fast:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim_gaia_import_export:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim_gaia_multi_seed:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
|
|
59
CHANGELOG.md
59
CHANGELOG.md
|
@ -1,5 +1,62 @@
|
|||
# Changelog
|
||||
|
||||
## 0.26.0
|
||||
|
||||
BREAKING CHANGES
|
||||
|
||||
* Gaia
|
||||
* [gaiad init] [\#2602](https://github.com/cosmos/cosmos-sdk/issues/2602) New genesis workflow
|
||||
|
||||
* SDK
|
||||
* [simulation] [\#2665](https://github.com/cosmos/cosmos-sdk/issues/2665) only argument to simulation.Invariant is now app
|
||||
|
||||
* Tendermint
|
||||
* Upgrade to version 0.26.0
|
||||
|
||||
FEATURES
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations
|
||||
* [cli] [\#2569](https://github.com/cosmos/cosmos-sdk/pull/2569) Add commands to query validator unbondings and redelegations
|
||||
* [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on.
|
||||
* [cli] [\#2558](https://github.com/cosmos/cosmos-sdk/issues/2558) Rename --print-sigs to --validate-signatures. It now performs a complete set of sanity checks and reports to the user. Also added --print-signature-only to print the signature only, not the whole transaction.
|
||||
|
||||
* SDK
|
||||
* [\#1336](https://github.com/cosmos/cosmos-sdk/issues/1336) Mechanism for SDK Users to configure their own Bech32 prefixes instead of using the default cosmos prefixes.
|
||||
|
||||
IMPROVEMENTS
|
||||
|
||||
* Gaia
|
||||
* [\#2637](https://github.com/cosmos/cosmos-sdk/issues/2637) [x/gov] Switched inactive and active proposal queues to an iterator based queue
|
||||
|
||||
* SDK
|
||||
* [\#2573](https://github.com/cosmos/cosmos-sdk/issues/2573) [x/distribution] add accum invariance
|
||||
* [\#2556](https://github.com/cosmos/cosmos-sdk/issues/2556) [x/mock/simulation] Fix debugging output
|
||||
* [\#2396](https://github.com/cosmos/cosmos-sdk/issues/2396) [x/mock/simulation] Change parameters to get more slashes
|
||||
* [\#2617](https://github.com/cosmos/cosmos-sdk/issues/2617) [x/mock/simulation] Randomize all genesis parameters
|
||||
* [\#2669](https://github.com/cosmos/cosmos-sdk/issues/2669) [x/stake] Added invarant check to make sure validator's power aligns with its spot in the power store.
|
||||
* [\#1924](https://github.com/cosmos/cosmos-sdk/issues/1924) [x/mock/simulation] Use a transition matrix for block size
|
||||
* [\#2660](https://github.com/cosmos/cosmos-sdk/issues/2660) [x/mock/simulation] Staking transactions get tested far more frequently
|
||||
* [\#2610](https://github.com/cosmos/cosmos-sdk/issues/2610) [x/stake] Block redelegation to and from the same validator
|
||||
* [\#2652](https://github.com/cosmos/cosmos-sdk/issues/2652) [x/auth] Add benchmark for get and set account
|
||||
* [\#2685](https://github.com/cosmos/cosmos-sdk/issues/2685) [store] Add general merkle absence proof (also for empty substores)
|
||||
* [\#2708](https://github.com/cosmos/cosmos-sdk/issues/2708) [store] Disallow setting nil values
|
||||
|
||||
BUG FIXES
|
||||
|
||||
* Gaia
|
||||
* [\#2670](https://github.com/cosmos/cosmos-sdk/issues/2670) [x/stake] fixed incorrect `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`
|
||||
* [\#2691](https://github.com/cosmos/cosmos-sdk/issues/2691) Fix local testnet creation by using a single canonical genesis time
|
||||
- [\#2670](https://github.com/cosmos/cosmos-sdk/issues/2670) [x/stake] fixed incorrent `IterateBondedValidators` and split into two functions: `IterateBondedValidators` and `IterateLastBlockConsValidators`
|
||||
- [\#2648](https://github.com/cosmos/cosmos-sdk/issues/2648) [gaiad] Fix `gaiad export` / `gaiad import` consistency, test in CI
|
||||
|
||||
* SDK
|
||||
* [\#2625](https://github.com/cosmos/cosmos-sdk/issues/2625) [x/gov] fix AppendTag function usage error
|
||||
* [\#2677](https://github.com/cosmos/cosmos-sdk/issues/2677) [x/stake, x/distribution] various staking/distribution fixes as found by the simulator
|
||||
* [\#2674](https://github.com/cosmos/cosmos-sdk/issues/2674) [types] Fix coin.IsLT() impl, coins.IsLT() impl, and renamed coins.Is\* to coins.IsAll\* (see [\#2686](https://github.com/cosmos/cosmos-sdk/issues/2686))
|
||||
* [\#2711](https://github.com/cosmos/cosmos-sdk/issues/2711) [x/stake] Add commission data to `MsgCreateValidator` signature bytes.
|
||||
* Temporarily disable insecure mode for Gaia Lite
|
||||
|
||||
## 0.25.0
|
||||
|
||||
*October 24th, 2018*
|
||||
|
@ -752,7 +809,7 @@ Update to Tendermint v0.19.4 (fixes a consensus bug and improves logging)
|
|||
|
||||
BREAKING CHANGES
|
||||
|
||||
* [stake] MarshalJSON -> MarshalBinary
|
||||
* [stake] MarshalJSON -> MarshalBinaryLengthPrefixed
|
||||
* Queries against the store must be prefixed with the path "/store"
|
||||
|
||||
FEATURES
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
revision = "48b08affede2cea076a3cf13b2e3f72ed262b743"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:09a7f74eb6bb3c0f14d8926610c87f569c5cff68e978d30e9a3540aeb626fdf0"
|
||||
name = "github.com/bartekn/go-bip39"
|
||||
packages = ["."]
|
||||
|
@ -38,7 +39,7 @@
|
|||
name = "github.com/btcsuite/btcd"
|
||||
packages = ["btcec"]
|
||||
pruneopts = "UT"
|
||||
revision = "2a560b2036bee5e3679ec2133eb6520b2f195213"
|
||||
revision = "67e573d211ace594f1366b4ce9d39726c4b19bd0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:386de157f7d19259a7f9c81f26ce011223ce0f090353c1152ffdf730d7d10ac2"
|
||||
|
@ -62,13 +63,6 @@
|
|||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c7644c73a3d23741fdba8a99b1464e021a224b7e205be497271a8003a15ca41b"
|
||||
name = "github.com/ebuchman/fail-test"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "95f809107225be108efcf10a3509e4ea6ceef3c4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd"
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
|
@ -245,12 +239,12 @@
|
|||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e32dfc6abff6a3633ef4d9a1022fd707c8ef26f1e1e8f855dc58dc415ce7c8f3"
|
||||
digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "fe40af7a9c397fa3ddba203c38a5042c5d0475ad"
|
||||
version = "v1.1.1"
|
||||
revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
|
||||
version = "v1.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
|
||||
|
@ -296,7 +290,7 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
|
||||
digest = "1:db712fde5d12d6cdbdf14b777f0c230f4ff5ab0be8e35b239fc319953ed577a4"
|
||||
name = "github.com/prometheus/common"
|
||||
packages = [
|
||||
"expfmt",
|
||||
|
@ -304,11 +298,11 @@
|
|||
"model",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
|
||||
revision = "7e9e6cabbd393fc208072eedef99188d0ce788b6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ef1dd9945e58ee9b635273d28c0ef3fa3742a7dedc038ebe207fd63e6ce000ef"
|
||||
digest = "1:ef74914912f99c79434d9c09658274678bc85080ebe3ab32bec3940ebce5e1fc"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [
|
||||
".",
|
||||
|
@ -317,7 +311,7 @@
|
|||
"xfs",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "418d78d0b9a7b7de3a6bbc8a23def624cc977bb2"
|
||||
revision = "185b4288413d2a0dd0806f78c90dde719829e5ae"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ea0700160aca4ef099f4e06686a665a87691f4248dddd40796925eda2e46bd64"
|
||||
|
@ -346,12 +340,12 @@
|
|||
version = "v1.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:516e71bed754268937f57d4ecb190e01958452336fa73dbac880894164e91c1f"
|
||||
digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
revision = "8c9545af88b134710ab1cd196795e7f2388358d7"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e"
|
||||
|
@ -370,12 +364,12 @@
|
|||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:dab83a1bbc7ad3d7a6ba1a1cc1760f25ac38cdf7d96a5cdd55cd915a4f5ceaf9"
|
||||
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
||||
version = "v1.0.2"
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f8e1a678a2571e265f4bf91a3e5e32aa6b1474a55cb0ea849750cc177b664d96"
|
||||
|
@ -424,35 +418,23 @@
|
|||
revision = "e5840949ff4fff0c56f9b6a541e22b63581ea9df"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:087aaa7920e5d0bf79586feb57ce01c35c830396ab4392798112e8aae8c47722"
|
||||
name = "github.com/tendermint/ed25519"
|
||||
packages = [
|
||||
".",
|
||||
"edwards25519",
|
||||
"extra25519",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2c971a45c89ca2ccc735af50919cdee05fbdc54d4bf50625073693300e31ead8"
|
||||
digest = "1:10b3a599325740c84a7c81f3f3cb2e1fdb70b3ea01b7fa28495567a2519df431"
|
||||
name = "github.com/tendermint/go-amino"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "faa6e731944e2b7b6a46ad202902851e8ce85bee"
|
||||
version = "v0.12.0"
|
||||
revision = "6dcc6ddc143e116455c94b25c1004c99e0d0ca12"
|
||||
version = "v0.14.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:53397098d6acb7613358683cc84ae59281a60c6033f0bff62fa8d3f279c6c430"
|
||||
digest = "1:9f8c4c93658315a795ffd3e0c943d39f78067dd8382b8d7bcfaf6686b92f3978"
|
||||
name = "github.com/tendermint/iavl"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "3acc91fb8811db2c5409a855ae1f8e441fe98e2d"
|
||||
version = "v0.11.0"
|
||||
revision = "fa74114f764f9827c4ad5573f990ed25bf8c4bac"
|
||||
version = "v0.11.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f9c7a1f3ee087476f4883c33cc7c1bdbe56b9670b2fb27855ea2f386393272f5"
|
||||
digest = "1:395820b381043b9d2204e181ddf0f9147397c4a7b8f5dc3162de4cfcddf4589a"
|
||||
name = "github.com/tendermint/tendermint"
|
||||
packages = [
|
||||
"abci/client",
|
||||
|
@ -485,6 +467,7 @@
|
|||
"libs/db",
|
||||
"libs/errors",
|
||||
"libs/events",
|
||||
"libs/fail",
|
||||
"libs/flowrate",
|
||||
"libs/log",
|
||||
"libs/pubsub",
|
||||
|
@ -505,7 +488,6 @@
|
|||
"rpc/core",
|
||||
"rpc/core/types",
|
||||
"rpc/grpc",
|
||||
"rpc/lib",
|
||||
"rpc/lib/client",
|
||||
"rpc/lib/server",
|
||||
"rpc/lib/types",
|
||||
|
@ -518,8 +500,8 @@
|
|||
"version",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "90eda9bfb6e6daeed1c8015df41cb36772d91778"
|
||||
version = "v0.25.1-rc0"
|
||||
revision = "03e42d2e3866f01a00625f608e3bbfaeb30690de"
|
||||
version = "v0.26.1-rc0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
|
||||
|
@ -530,13 +512,15 @@
|
|||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:aaff04fa01d9b824fde6799759cc597b3ac3671b9ad31924c28b6557d0ee5284"
|
||||
digest = "1:6f6dc6060c4e9ba73cf28aa88f12a69a030d3d19d518ef8e931879eaa099628d"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"bcrypt",
|
||||
"blowfish",
|
||||
"chacha20poly1305",
|
||||
"curve25519",
|
||||
"ed25519",
|
||||
"ed25519/internal/edwards25519",
|
||||
"hkdf",
|
||||
"internal/chacha20",
|
||||
"internal/subtle",
|
||||
|
@ -705,6 +689,7 @@
|
|||
"github.com/tendermint/tendermint/rpc/lib/client",
|
||||
"github.com/tendermint/tendermint/rpc/lib/server",
|
||||
"github.com/tendermint/tendermint/types",
|
||||
"github.com/tendermint/tendermint/types/time",
|
||||
"github.com/tendermint/tendermint/version",
|
||||
"github.com/zondax/ledger-goclient",
|
||||
"golang.org/x/crypto/bcrypt",
|
||||
|
|
29
Gopkg.toml
29
Gopkg.toml
|
@ -1,24 +1,3 @@
|
|||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/bgentry/speakeasy"
|
||||
version = "~0.1.0"
|
||||
|
@ -49,15 +28,15 @@
|
|||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/go-amino"
|
||||
version = "=v0.12.0"
|
||||
version = "v0.14.0"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/iavl"
|
||||
version = "=v0.11.0"
|
||||
version = "=v0.11.1"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
version = "=0.25.1-rc0"
|
||||
version = "v0.26.1-rc0" # TODO replace w/ 0.26.1
|
||||
|
||||
## deps without releases:
|
||||
|
||||
|
@ -89,7 +68,6 @@
|
|||
version = "1.0.0"
|
||||
|
||||
## transitive deps, without releases:
|
||||
#
|
||||
|
||||
[[override]]
|
||||
name = "github.com/syndtr/goleveldb"
|
||||
|
@ -106,4 +84,3 @@
|
|||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
|
|
18
Makefile
18
Makefile
|
@ -169,13 +169,22 @@ test_sim_gaia_nondeterminism:
|
|||
|
||||
test_sim_gaia_fast:
|
||||
@echo "Running quick Gaia simulation. This may take several minutes..."
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=400 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=9 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=500 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=10 -v -timeout 24h
|
||||
|
||||
test_sim_gaia_import_export:
|
||||
@echo "Running Gaia import/export simulation. This may take several minutes..."
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=4 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=11 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=12 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=13 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=414 -v -timeout 24h
|
||||
@go test ./cmd/gaia/app -run TestGaiaImportExport -SimulationEnabled=true -SimulationNumBlocks=50 -SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=4142 -v -timeout 24h
|
||||
|
||||
test_sim_gaia_multi_seed:
|
||||
@echo "Running multi-seed Gaia simulation. This may take awhile!"
|
||||
@bash scripts/multisim.sh 10
|
||||
@bash scripts/multisim.sh 25
|
||||
|
||||
SIM_NUM_BLOCKS ?= 210
|
||||
SIM_NUM_BLOCKS ?= 500
|
||||
SIM_BLOCK_SIZE ?= 200
|
||||
SIM_COMMIT ?= true
|
||||
test_sim_gaia_benchmark:
|
||||
|
@ -250,4 +259,5 @@ localnet-stop:
|
|||
check_tools check_dev_tools get_tools get_dev_tools get_vendor_deps draw_deps test test_cli test_unit \
|
||||
test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \
|
||||
build-linux build-docker-gaiadnode localnet-start localnet-stop \
|
||||
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast test_sim_gaia_multi_seed update_tools update_dev_tools
|
||||
format check-ledger test_sim_gaia_nondeterminism test_sim_modules test_sim_gaia_fast \
|
||||
test_sim_gaia_multi_seed test_sim_gaia_import_export update_tools update_dev_tools
|
||||
|
|
|
@ -337,7 +337,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc
|
|||
}
|
||||
|
||||
// Encode with json
|
||||
value := codec.Cdc.MustMarshalBinary(result)
|
||||
value := codec.Cdc.MustMarshalBinaryLengthPrefixed(result)
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(sdk.ABCICodeOK),
|
||||
Value: value,
|
||||
|
@ -394,6 +394,7 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
|
|||
|
||||
ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger).
|
||||
WithMinimumFees(app.minimumFees)
|
||||
|
||||
// Passes the rest of the path as an argument to the querier.
|
||||
// For example, in the path "custom/gov/proposal/test", the gov querier gets []string{"proposal", "test"} as the path
|
||||
resBytes, err := querier(ctx, path[2:], req)
|
||||
|
|
|
@ -358,7 +358,7 @@ func testTxDecoder(cdc *codec.Codec) sdk.TxDecoder {
|
|||
if len(txBytes) == 0 {
|
||||
return nil, sdk.ErrTxDecode("txBytes are empty")
|
||||
}
|
||||
err := cdc.UnmarshalBinary(txBytes, &tx)
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrTxDecode("").TraceSDK(err.Error())
|
||||
}
|
||||
|
@ -455,7 +455,7 @@ func TestCheckTx(t *testing.T) {
|
|||
|
||||
for i := int64(0); i < nTxs; i++ {
|
||||
tx := newTxCounter(i, 0)
|
||||
txBytes, err := codec.MarshalBinary(tx)
|
||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
r := app.CheckTx(txBytes)
|
||||
assert.True(t, r.IsOK(), fmt.Sprintf("%v", r))
|
||||
|
@ -503,7 +503,7 @@ func TestDeliverTx(t *testing.T) {
|
|||
for i := 0; i < txPerHeight; i++ {
|
||||
counter := int64(blockN*txPerHeight + i)
|
||||
tx := newTxCounter(counter, counter)
|
||||
txBytes, err := codec.MarshalBinary(tx)
|
||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
res := app.DeliverTx(txBytes)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
@ -544,7 +544,7 @@ func TestMultiMsgDeliverTx(t *testing.T) {
|
|||
{
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
tx := newTxCounter(0, 0, 1, 2)
|
||||
txBytes, err := codec.MarshalBinary(tx)
|
||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
res := app.DeliverTx(txBytes)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
@ -565,7 +565,7 @@ func TestMultiMsgDeliverTx(t *testing.T) {
|
|||
tx := newTxCounter(1, 3)
|
||||
tx.Msgs = append(tx.Msgs, msgCounter2{0})
|
||||
tx.Msgs = append(tx.Msgs, msgCounter2{1})
|
||||
txBytes, err := codec.MarshalBinary(tx)
|
||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
res := app.DeliverTx(txBytes)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
@ -638,7 +638,7 @@ func TestSimulateTx(t *testing.T) {
|
|||
require.Equal(t, gasConsumed, result.GasUsed)
|
||||
|
||||
// simulate by calling Query with encoded tx
|
||||
txBytes, err := cdc.MarshalBinary(tx)
|
||||
txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx)
|
||||
require.Nil(t, err)
|
||||
query := abci.RequestQuery{
|
||||
Path: "/app/simulate",
|
||||
|
@ -648,7 +648,7 @@ func TestSimulateTx(t *testing.T) {
|
|||
require.True(t, queryResult.IsOK(), queryResult.Log)
|
||||
|
||||
var res sdk.Result
|
||||
codec.Cdc.MustUnmarshalBinary(queryResult.Value, &res)
|
||||
codec.Cdc.MustUnmarshalBinaryLengthPrefixed(queryResult.Value, &res)
|
||||
require.Nil(t, err, "Result unmarshalling failed")
|
||||
require.True(t, res.IsOK(), res.Log)
|
||||
require.Equal(t, gasConsumed, res.GasUsed, res.Log)
|
||||
|
@ -729,7 +729,7 @@ func TestRunInvalidTransaction(t *testing.T) {
|
|||
registerTestCodec(newCdc)
|
||||
newCdc.RegisterConcrete(&msgNoDecode{}, "cosmos-sdk/baseapp/msgNoDecode", nil)
|
||||
|
||||
txBytes, err := newCdc.MarshalBinary(tx)
|
||||
txBytes, err := newCdc.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
res := app.DeliverTx(txBytes)
|
||||
require.EqualValues(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeTxDecode), res.Code)
|
||||
|
|
|
@ -121,8 +121,13 @@ func createVerifier() tmlite.Verifier {
|
|||
fmt.Printf("Must specify these options: %s when --trust-node is false\n", errMsg.String())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
node := rpcclient.NewHTTP(nodeURI, "/websocket")
|
||||
verifier, err := tmliteProxy.NewVerifier(chainID, filepath.Join(home, ".gaialite"), node, log.NewNopLogger())
|
||||
cacheSize := 10 // TODO: determine appropriate cache size
|
||||
verifier, err := tmliteProxy.NewVerifier(
|
||||
chainID, filepath.Join(home, ".gaialite"),
|
||||
node, log.NewNopLogger(), cacheSize,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Create verifier failed: %s\n", err.Error())
|
||||
|
|
|
@ -10,9 +10,9 @@ import (
|
|||
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
tmliteErr "github.com/tendermint/tendermint/lite/errors"
|
||||
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
||||
|
@ -54,7 +54,7 @@ func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sd
|
|||
return res, err
|
||||
}
|
||||
|
||||
ctx.Codec.MustUnmarshalBinary(resRaw, &res)
|
||||
ctx.Codec.MustUnmarshalBinaryLengthPrefixed(resRaw, &res)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -157,8 +157,8 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
|
|||
}
|
||||
|
||||
opts := rpcclient.ABCIQueryOptions{
|
||||
Height: ctx.Height,
|
||||
Trusted: ctx.TrustNode,
|
||||
Height: ctx.Height,
|
||||
Prove: !ctx.TrustNode,
|
||||
}
|
||||
|
||||
result, err := node.ABCIQueryWithOptions(path, key, opts)
|
||||
|
@ -198,7 +198,7 @@ func (ctx CLIContext) Verify(height int64) (tmtypes.SignedHeader, error) {
|
|||
}
|
||||
|
||||
// verifyProof perform response proof verification.
|
||||
func (ctx CLIContext) verifyProof(_ string, resp abci.ResponseQuery) error {
|
||||
func (ctx CLIContext) verifyProof(queryPath string, resp abci.ResponseQuery) error {
|
||||
if ctx.Verifier == nil {
|
||||
return fmt.Errorf("missing valid certifier to verify data from distrusted node")
|
||||
}
|
||||
|
@ -209,25 +209,22 @@ func (ctx CLIContext) verifyProof(_ string, resp abci.ResponseQuery) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var multiStoreProof store.MultiStoreProof
|
||||
cdc := codec.New()
|
||||
// TODO: Instead of reconstructing, stash on CLIContext field?
|
||||
prt := store.DefaultProofRuntime()
|
||||
|
||||
err = cdc.UnmarshalBinary(resp.Proof, &multiStoreProof)
|
||||
// TODO: Better convention for path?
|
||||
storeName, err := parseQueryStorePath(queryPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to unmarshalBinary rangeProof")
|
||||
return err
|
||||
}
|
||||
|
||||
// verify the substore commit hash against trusted appHash
|
||||
substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(
|
||||
multiStoreProof.StoreName, multiStoreProof.StoreInfos, commit.Header.AppHash,
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed in verifying the proof against appHash")
|
||||
}
|
||||
kp := merkle.KeyPath{}
|
||||
kp = kp.AppendKey([]byte(storeName), merkle.KeyEncodingURL)
|
||||
kp = kp.AppendKey(resp.Key, merkle.KeyEncodingURL)
|
||||
|
||||
err = store.VerifyRangeProof(resp.Key, resp.Value, substoreCommitHash, &multiStoreProof.RangeProof)
|
||||
err = prt.VerifyValue(resp.Proof, commit.Header.AppHash, kp.String(), resp.Value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed in the range proof verification")
|
||||
return errors.Wrap(err, "failed to prove merkle proof")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -241,20 +238,40 @@ func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([
|
|||
}
|
||||
|
||||
// isQueryStoreWithProof expects a format like /<queryType>/<storeName>/<subpath>
|
||||
// queryType can be app or store.
|
||||
// queryType must be "store" and subpath must be "key" to require a proof.
|
||||
func isQueryStoreWithProof(path string) bool {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
return false
|
||||
}
|
||||
|
||||
paths := strings.SplitN(path[1:], "/", 3)
|
||||
if len(paths) != 3 {
|
||||
switch {
|
||||
case len(paths) != 3:
|
||||
return false
|
||||
}
|
||||
|
||||
if store.RequireProof("/" + paths[2]) {
|
||||
case paths[0] != "store":
|
||||
return false
|
||||
case store.RequireProof("/" + paths[2]):
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// parseQueryStorePath expects a format like /store/<storeName>/key.
|
||||
func parseQueryStorePath(path string) (storeName string, err error) {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
return "", errors.New("expected path to start with /")
|
||||
}
|
||||
|
||||
paths := strings.SplitN(path[1:], "/", 3)
|
||||
switch {
|
||||
case len(paths) != 3:
|
||||
return "", errors.New("expected format like /store/<storeName>/key")
|
||||
case paths[0] != "store":
|
||||
return "", errors.New("expected format like /store/<storeName>/key")
|
||||
case paths[2] != "key":
|
||||
return "", errors.New("expected format like /store/<storeName>/key")
|
||||
}
|
||||
|
||||
return paths[1], nil
|
||||
}
|
||||
|
|
|
@ -96,7 +96,12 @@ func GetKeyBaseFromDirWithWritePerm(rootDir string) (keys.Keybase, error) {
|
|||
|
||||
// GetKeyBaseFromDir initializes a read-only keybase at a particular dir.
|
||||
func GetKeyBaseFromDir(rootDir string) (keys.Keybase, error) {
|
||||
return getKeyBaseFromDirWithOpts(rootDir, &opt.Options{ReadOnly: true})
|
||||
// Disabled because of the inability to create a new keys database directory
|
||||
// in the instance of when ReadOnly is set to true.
|
||||
//
|
||||
// ref: syndtr/goleveldb#240
|
||||
// return getKeyBaseFromDirWithOpts(rootDir, &opt.Options{ReadOnly: true})
|
||||
return getKeyBaseFromDirWithOpts(rootDir, nil)
|
||||
}
|
||||
|
||||
func getKeyBaseFromDirWithOpts(rootDir string, o *opt.Options) (keys.Keybase, error) {
|
||||
|
|
|
@ -38,6 +38,7 @@ func generateSelfSignedCert(host string) (certBytes []byte, priv *ecdsa.PrivateK
|
|||
Subject: pkix.Name{
|
||||
Organization: []string{"Gaia Lite"},
|
||||
},
|
||||
DNSNames: []string{"localhost"},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
|
|
|
@ -17,7 +17,7 @@ func TestGenerateSelfSignedCert(t *testing.T) {
|
|||
cert, err := x509.ParseCertificate(certBytes)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, 2, len(cert.IPAddresses))
|
||||
require.Equal(t, 1, len(cert.DNSNames))
|
||||
require.Equal(t, 2, len(cert.DNSNames))
|
||||
require.True(t, cert.IsCA)
|
||||
}
|
||||
|
||||
|
|
|
@ -158,11 +158,11 @@ func TestNodeStatus(t *testing.T) {
|
|||
res, body := Request(t, port, "GET", "/node_info", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var nodeInfo p2p.NodeInfo
|
||||
var nodeInfo p2p.DefaultNodeInfo
|
||||
err := cdc.UnmarshalJSON([]byte(body), &nodeInfo)
|
||||
require.Nil(t, err, "Couldn't parse node info")
|
||||
|
||||
require.NotEqual(t, p2p.NodeInfo{}, nodeInfo, "res: %v", res)
|
||||
require.NotEqual(t, p2p.DefaultNodeInfo{}, nodeInfo, "res: %v", res)
|
||||
|
||||
// syncing
|
||||
res, body = Request(t, port, "GET", "/syncing", nil)
|
||||
|
@ -628,8 +628,8 @@ func TestSubmitProposal(t *testing.T) {
|
|||
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||
|
||||
var proposalID int64
|
||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID)
|
||||
var proposalID uint64
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
|
||||
|
||||
// query proposal
|
||||
proposal := getProposal(t, port, proposalID)
|
||||
|
@ -650,8 +650,8 @@ func TestDeposit(t *testing.T) {
|
|||
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||
|
||||
var proposalID int64
|
||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID)
|
||||
var proposalID uint64
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
|
||||
|
||||
// query proposal
|
||||
proposal := getProposal(t, port, proposalID)
|
||||
|
@ -684,8 +684,8 @@ func TestVote(t *testing.T) {
|
|||
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||
|
||||
var proposalID int64
|
||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID)
|
||||
var proposalID uint64
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
|
||||
|
||||
// query proposal
|
||||
proposal := getProposal(t, port, proposalID)
|
||||
|
@ -732,18 +732,18 @@ func TestProposalsQuery(t *testing.T) {
|
|||
|
||||
// Addr1 proposes (and deposits) proposals #1 and #2
|
||||
resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], 5)
|
||||
var proposalID1 int64
|
||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1)
|
||||
var proposalID1 uint64
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID1)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], 5)
|
||||
var proposalID2 int64
|
||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2)
|
||||
var proposalID2 uint64
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID2)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
// Addr2 proposes (and deposits) proposals #3
|
||||
resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], 5)
|
||||
var proposalID3 int64
|
||||
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3)
|
||||
var proposalID3 uint64
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID3)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
// Addr2 deposits on proposals #2 & #3
|
||||
|
@ -1230,7 +1230,7 @@ func getValidatorRedelegations(t *testing.T, port string, validatorAddr sdk.ValA
|
|||
|
||||
// ============= Governance Module ================
|
||||
|
||||
func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
|
||||
func getProposal(t *testing.T, port string, proposalID uint64) gov.Proposal {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d", proposalID), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var proposal gov.Proposal
|
||||
|
@ -1239,7 +1239,7 @@ func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
|
|||
return proposal
|
||||
}
|
||||
|
||||
func getDeposits(t *testing.T, port string, proposalID int64) []gov.Deposit {
|
||||
func getDeposits(t *testing.T, port string, proposalID uint64) []gov.Deposit {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var deposits []gov.Deposit
|
||||
|
@ -1248,7 +1248,7 @@ func getDeposits(t *testing.T, port string, proposalID int64) []gov.Deposit {
|
|||
return deposits
|
||||
}
|
||||
|
||||
func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.AccAddress) gov.Deposit {
|
||||
func getDeposit(t *testing.T, port string, proposalID uint64, depositerAddr sdk.AccAddress) gov.Deposit {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var deposit gov.Deposit
|
||||
|
@ -1257,7 +1257,7 @@ func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.A
|
|||
return deposit
|
||||
}
|
||||
|
||||
func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.AccAddress) gov.Vote {
|
||||
func getVote(t *testing.T, port string, proposalID uint64, voterAddr sdk.AccAddress) gov.Vote {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes/%s", proposalID, voterAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var vote gov.Vote
|
||||
|
@ -1266,7 +1266,7 @@ func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.AccAddre
|
|||
return vote
|
||||
}
|
||||
|
||||
func getVotes(t *testing.T, port string, proposalID int64) []gov.Vote {
|
||||
func getVotes(t *testing.T, port string, proposalID uint64) []gov.Vote {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var votes []gov.Vote
|
||||
|
@ -1358,7 +1358,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
|
|||
return results
|
||||
}
|
||||
|
||||
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||
|
||||
acc := getAccount(t, port, proposerAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
|
@ -1388,7 +1388,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
|
|||
return results
|
||||
}
|
||||
|
||||
func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||
func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64) (resultTx ctypes.ResultBroadcastTxCommit) {
|
||||
// get the account to get the sequence
|
||||
acc := getAccount(t, port, proposerAddr)
|
||||
accnum := acc.GetAccountNumber()
|
||||
|
|
|
@ -2,6 +2,7 @@ package lcd
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||
|
@ -21,7 +23,6 @@ import (
|
|||
"github.com/rakyll/statik/fs"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
)
|
||||
|
@ -47,24 +48,38 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
|||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
listenAddr := viper.GetString(flagListenAddr)
|
||||
handler := createHandler(cdc)
|
||||
|
||||
registerSwaggerUI(handler)
|
||||
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
|
||||
maxOpen := viper.GetInt(flagMaxOpenConnections)
|
||||
sslHosts := viper.GetString(flagSSLHosts)
|
||||
certFile := viper.GetString(flagSSLCertFile)
|
||||
keyFile := viper.GetString(flagSSLKeyFile)
|
||||
cleanupFunc := func() {}
|
||||
|
||||
var listener net.Listener
|
||||
var fingerprint string
|
||||
|
||||
server.TrapSignal(func() {
|
||||
err := listener.Close()
|
||||
logger.Error("error closing listener", "err", err)
|
||||
})
|
||||
|
||||
var cleanupFunc func()
|
||||
|
||||
// TODO: re-enable insecure mode once #2715 has been addressed
|
||||
if viper.GetBool(flagInsecure) {
|
||||
listener, err = tmserver.StartHTTPServer(
|
||||
listenAddr, handler, logger,
|
||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
fmt.Println(
|
||||
"Insecure mode is temporarily disabled, please locally generate an " +
|
||||
"SSL certificate to test. Support will be re-enabled soon!",
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// listener, err = tmserver.StartHTTPServer(
|
||||
// listenAddr, handler, logger,
|
||||
// tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
// )
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
} else {
|
||||
if certFile != "" {
|
||||
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
|
||||
|
@ -72,6 +87,7 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// cert/key pair is provided, read the fingerprint
|
||||
fingerprint, err = fingerprintFromFile(certFile)
|
||||
if err != nil {
|
||||
|
@ -83,12 +99,15 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cleanupFunc = func() {
|
||||
os.Remove(certFile)
|
||||
os.Remove(keyFile)
|
||||
}
|
||||
|
||||
defer cleanupFunc()
|
||||
}
|
||||
|
||||
listener, err = tmserver.StartHTTPAndTLSServer(
|
||||
listenAddr, handler,
|
||||
certFile, keyFile,
|
||||
|
@ -98,16 +117,12 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
logger.Info(fingerprint)
|
||||
}
|
||||
logger.Info("REST server started")
|
||||
|
||||
// wait forever and cleanup
|
||||
cmn.TrapSignal(func() {
|
||||
defer cleanupFunc()
|
||||
err := listener.Close()
|
||||
logger.Error("error closing listener", "err", err)
|
||||
})
|
||||
logger.Info(fingerprint)
|
||||
logger.Info("REST server started")
|
||||
}
|
||||
|
||||
// logger.Info("REST server started")
|
||||
|
||||
return nil
|
||||
},
|
||||
|
@ -124,6 +139,7 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
|||
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
|
||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||
cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response")
|
||||
|
||||
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
|
||||
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
|
||||
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
|
||||
|
|
|
@ -214,6 +214,7 @@ func InitializeTestLCD(
|
|||
genTxs := []json.RawMessage{}
|
||||
|
||||
// append any additional (non-proposing) validators
|
||||
var accs []gapp.GenesisAccount
|
||||
for i := 0; i < nValidators; i++ {
|
||||
operPrivKey := secp256k1.GenPrivKey()
|
||||
operAddr := operPrivKey.PubKey().Address()
|
||||
|
@ -242,9 +243,17 @@ func InitializeTestLCD(
|
|||
genTxs = append(genTxs, txBytes)
|
||||
valConsPubKeys = append(valConsPubKeys, pubKey)
|
||||
valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr))
|
||||
|
||||
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr))
|
||||
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 150)}
|
||||
accs = append(accs, gapp.NewGenesisAccount(&accAuth))
|
||||
}
|
||||
|
||||
genesisState, err := gapp.GaiaAppGenState(cdc, genTxs)
|
||||
appGenState := gapp.NewDefaultGenesisState()
|
||||
appGenState.Accounts = accs
|
||||
genDoc.AppState, err = cdc.MarshalJSON(appGenState)
|
||||
require.NoError(t, err)
|
||||
genesisState, err := gapp.GaiaAppGenState(cdc, *genDoc, genTxs)
|
||||
require.NoError(t, err)
|
||||
|
||||
// add some tokens to init accounts
|
||||
|
|
|
@ -125,7 +125,7 @@ type Info struct {
|
|||
func parseTx(cdc *codec.Codec, txBytes []byte) (sdk.Tx, error) {
|
||||
var tx auth.StdTx
|
||||
|
||||
err := cdc.UnmarshalBinary(txBytes, &tx)
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -65,6 +65,20 @@ func ParseInt64OrReturnBadRequest(w http.ResponseWriter, s string) (n int64, ok
|
|||
return n, true
|
||||
}
|
||||
|
||||
// ParseUint64OrReturnBadRequest converts s to a uint64 value.
|
||||
func ParseUint64OrReturnBadRequest(w http.ResponseWriter, s string) (n uint64, ok bool) {
|
||||
var err error
|
||||
|
||||
n, err = strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("'%s' is not a valid uint64", s)
|
||||
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return n, false
|
||||
}
|
||||
|
||||
return n, true
|
||||
}
|
||||
|
||||
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a
|
||||
// default value, defaultIfEmpty, if the string is empty.
|
||||
func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) {
|
||||
|
|
|
@ -123,7 +123,8 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
|||
|
||||
// Check whether the address is a signer
|
||||
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
|
||||
fmt.Fprintf(os.Stderr, "WARNING: The generated transaction's intended signer does not match the given signer: '%v'\n", name)
|
||||
return signedStdTx, fmt.Errorf(
|
||||
"The generated transaction's intended signer does not match the given signer: %q", name)
|
||||
}
|
||||
|
||||
if !offline && txBldr.AccountNumber == 0 {
|
||||
|
@ -166,7 +167,7 @@ func adjustGasEstimate(estimate int64, adjustment float64) int64 {
|
|||
|
||||
func parseQueryResponse(cdc *amino.Codec, rawRes []byte) (int64, error) {
|
||||
var simulationResult sdk.Result
|
||||
if err := cdc.UnmarshalBinary(rawRes, &simulationResult); err != nil {
|
||||
if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &simulationResult); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return simulationResult.GasUsed, nil
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
func TestParseQueryResponse(t *testing.T) {
|
||||
cdc := app.MakeCodec()
|
||||
sdkResBytes := cdc.MustMarshalBinary(sdk.Result{GasUsed: 10})
|
||||
sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: 10})
|
||||
gas, err := parseQueryResponse(cdc, sdkResBytes)
|
||||
assert.Equal(t, gas, int64(10))
|
||||
assert.Nil(t, err)
|
||||
|
@ -28,7 +28,7 @@ func TestCalculateGas(t *testing.T) {
|
|||
if wantErr {
|
||||
return nil, errors.New("")
|
||||
}
|
||||
return cdc.MustMarshalBinary(sdk.Result{GasUsed: gasUsed}), nil
|
||||
return cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: gasUsed}), nil
|
||||
}
|
||||
}
|
||||
type args struct {
|
||||
|
|
|
@ -109,7 +109,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
app.cdc,
|
||||
app.keyParams, app.tkeyParams,
|
||||
)
|
||||
app.stakeKeeper = stake.NewKeeper(
|
||||
stakeKeeper := stake.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyStake, app.tkeyStake,
|
||||
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
|
||||
|
@ -117,30 +117,32 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
)
|
||||
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
|
||||
app.paramsKeeper.Subspace(mint.DefaultParamspace),
|
||||
app.stakeKeeper, app.feeCollectionKeeper,
|
||||
&stakeKeeper, app.feeCollectionKeeper,
|
||||
)
|
||||
app.distrKeeper = distr.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyDistr,
|
||||
app.paramsKeeper.Subspace(distr.DefaultParamspace),
|
||||
app.bankKeeper, app.stakeKeeper, app.feeCollectionKeeper,
|
||||
app.bankKeeper, &stakeKeeper, app.feeCollectionKeeper,
|
||||
app.RegisterCodespace(stake.DefaultCodespace),
|
||||
)
|
||||
app.slashingKeeper = slashing.NewKeeper(
|
||||
app.cdc,
|
||||
app.keySlashing,
|
||||
app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
|
||||
&stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
|
||||
app.RegisterCodespace(slashing.DefaultCodespace),
|
||||
)
|
||||
app.govKeeper = gov.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyGov,
|
||||
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, app.stakeKeeper,
|
||||
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakeKeeper,
|
||||
app.RegisterCodespace(gov.DefaultCodespace),
|
||||
)
|
||||
|
||||
// register the staking hooks
|
||||
app.stakeKeeper = app.stakeKeeper.WithHooks(
|
||||
// NOTE: stakeKeeper above are passed by reference,
|
||||
// so that it can be modified like below:
|
||||
app.stakeKeeper = *stakeKeeper.SetHooks(
|
||||
NewHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))
|
||||
|
||||
// register message routes
|
||||
|
@ -208,9 +210,6 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R
|
|||
tags := gov.EndBlocker(ctx, app.govKeeper)
|
||||
validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper)
|
||||
|
||||
// Add these new validators to the addr -> pubkey map.
|
||||
app.slashingKeeper.AddValidators(ctx, validatorUpdates)
|
||||
|
||||
return abci.ResponseEndBlock{
|
||||
ValidatorUpdates: validatorUpdates,
|
||||
Tags: tags,
|
||||
|
@ -229,6 +228,10 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
|
||||
// sort by account number to maintain consistency
|
||||
sort.Slice(genesisState.Accounts, func(i, j int) bool {
|
||||
return genesisState.Accounts[i].AccountNumber < genesisState.Accounts[j].AccountNumber
|
||||
})
|
||||
// load the accounts
|
||||
for _, gacc := range genesisState.Accounts {
|
||||
acc := gacc.ToAccount()
|
||||
|
@ -242,7 +245,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
panic(err) // TODO find a way to do this w/o panics
|
||||
}
|
||||
|
||||
// load the address to pubkey map
|
||||
// initialize module-specific stores
|
||||
auth.InitGenesis(ctx, app.feeCollectionKeeper, genesisState.AuthData)
|
||||
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
|
||||
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
|
||||
|
@ -259,7 +263,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bz := app.cdc.MustMarshalBinary(tx)
|
||||
bz := app.cdc.MustMarshalBinaryLengthPrefixed(tx)
|
||||
res := app.BaseApp.DeliverTx(bz)
|
||||
if !res.IsOK() {
|
||||
panic(res.Log)
|
||||
|
@ -268,12 +272,12 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
|
||||
validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
}
|
||||
app.slashingKeeper.AddValidators(ctx, validators)
|
||||
|
||||
// sanity check
|
||||
if len(req.Validators) > 0 {
|
||||
if len(req.Validators) != len(validators) {
|
||||
panic(fmt.Errorf("len(RequestInitChain.Validators) != len(validators) (%d != %d) ", len(req.Validators), len(validators)))
|
||||
panic(fmt.Errorf("len(RequestInitChain.Validators) != len(validators) (%d != %d)",
|
||||
len(req.Validators), len(validators)))
|
||||
}
|
||||
sort.Sort(abci.ValidatorUpdates(req.Validators))
|
||||
sort.Sort(abci.ValidatorUpdates(validators))
|
||||
|
@ -303,11 +307,12 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val
|
|||
app.accountKeeper.IterateAccounts(ctx, appendAccount)
|
||||
genState := NewGenesisState(
|
||||
accounts,
|
||||
stake.WriteGenesis(ctx, app.stakeKeeper),
|
||||
mint.WriteGenesis(ctx, app.mintKeeper),
|
||||
distr.WriteGenesis(ctx, app.distrKeeper),
|
||||
gov.WriteGenesis(ctx, app.govKeeper),
|
||||
slashing.GenesisState{}, // TODO create write methods
|
||||
auth.ExportGenesis(ctx, app.feeCollectionKeeper),
|
||||
stake.ExportGenesis(ctx, app.stakeKeeper),
|
||||
mint.ExportGenesis(ctx, app.mintKeeper),
|
||||
distr.ExportGenesis(ctx, app.distrKeeper),
|
||||
gov.ExportGenesis(ctx, app.govKeeper),
|
||||
slashing.ExportGenesis(ctx, app.slashingKeeper),
|
||||
)
|
||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
|
@ -334,12 +339,15 @@ var _ sdk.StakingHooks = Hooks{}
|
|||
// nolint
|
||||
func (h Hooks) OnValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorCreated(ctx, valAddr)
|
||||
h.sh.OnValidatorCreated(ctx, valAddr)
|
||||
}
|
||||
func (h Hooks) OnValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorModified(ctx, valAddr)
|
||||
h.sh.OnValidatorModified(ctx, valAddr)
|
||||
}
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorRemoved(ctx, valAddr)
|
||||
func (h Hooks) OnValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorRemoved(ctx, consAddr, valAddr)
|
||||
h.sh.OnValidatorRemoved(ctx, consAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnValidatorBonded(ctx, consAddr, valAddr)
|
||||
|
@ -355,10 +363,13 @@ func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddre
|
|||
}
|
||||
func (h Hooks) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationCreated(ctx, delAddr, valAddr)
|
||||
h.sh.OnDelegationCreated(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
h.sh.OnDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h Hooks) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.OnDelegationRemoved(ctx, delAddr, valAddr)
|
||||
h.sh.OnDelegationRemoved(ctx, delAddr, valAddr)
|
||||
}
|
||||
|
|
|
@ -26,11 +26,13 @@ var (
|
|||
// bonded tokens given to genesis validators/accounts
|
||||
freeFermionVal = int64(100)
|
||||
freeFermionsAcc = sdk.NewInt(150)
|
||||
bondDenom = "steak"
|
||||
)
|
||||
|
||||
// State to Unmarshal
|
||||
type GenesisState struct {
|
||||
Accounts []GenesisAccount `json:"accounts"`
|
||||
AuthData auth.GenesisState `json:"auth"`
|
||||
StakeData stake.GenesisState `json:"stake"`
|
||||
MintData mint.GenesisState `json:"mint"`
|
||||
DistrData distr.GenesisState `json:"distr"`
|
||||
|
@ -39,11 +41,12 @@ type GenesisState struct {
|
|||
GenTxs []json.RawMessage `json:"gentxs"`
|
||||
}
|
||||
|
||||
func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mintData mint.GenesisState,
|
||||
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, stakeData stake.GenesisState, mintData mint.GenesisState,
|
||||
distrData distr.GenesisState, govData gov.GenesisState, slashingData slashing.GenesisState) GenesisState {
|
||||
|
||||
return GenesisState{
|
||||
Accounts: accounts,
|
||||
AuthData: authData,
|
||||
StakeData: stakeData,
|
||||
MintData: mintData,
|
||||
DistrData: distrData,
|
||||
|
@ -52,31 +55,39 @@ func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mi
|
|||
}
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
// nolint
|
||||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
Sequence int64 `json:"sequence_number"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
}
|
||||
|
||||
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
Address: acc.Address,
|
||||
Coins: acc.Coins,
|
||||
Address: acc.Address,
|
||||
Coins: acc.Coins,
|
||||
AccountNumber: acc.AccountNumber,
|
||||
Sequence: acc.Sequence,
|
||||
}
|
||||
}
|
||||
|
||||
func NewGenesisAccountI(acc auth.Account) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
Address: acc.GetAddress(),
|
||||
Coins: acc.GetCoins(),
|
||||
Address: acc.GetAddress(),
|
||||
Coins: acc.GetCoins(),
|
||||
AccountNumber: acc.GetAccountNumber(),
|
||||
Sequence: acc.GetSequence(),
|
||||
}
|
||||
}
|
||||
|
||||
// convert GenesisAccount to auth.BaseAccount
|
||||
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
|
||||
return &auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
AccountNumber: ga.AccountNumber,
|
||||
Sequence: ga.Sequence,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,58 +101,60 @@ func GaiaAppInit() server.AppInit {
|
|||
|
||||
// Create the core parameters for genesis initialization for gaia
|
||||
// note that the pubkey input is this machines pubkey
|
||||
func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisState GenesisState, err error) {
|
||||
if len(appGenTxs) == 0 {
|
||||
err = errors.New("must provide at least genesis transaction")
|
||||
return
|
||||
func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
genesisState GenesisState, err error) {
|
||||
|
||||
if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
|
||||
return genesisState, err
|
||||
}
|
||||
|
||||
// start with the default staking genesis state
|
||||
stakeData := stake.DefaultGenesisState()
|
||||
slashingData := slashing.DefaultGenesisState()
|
||||
|
||||
// get genesis flag account information
|
||||
genaccs := make([]GenesisAccount, len(appGenTxs))
|
||||
// if there are no gen txs to be processed, return the default empty state
|
||||
if len(appGenTxs) == 0 {
|
||||
return genesisState, errors.New("there must be at least one genesis tx")
|
||||
}
|
||||
|
||||
stakeData := genesisState.StakeData
|
||||
for i, genTx := range appGenTxs {
|
||||
var tx auth.StdTx
|
||||
err = cdc.UnmarshalJSON(genTx, &tx)
|
||||
if err != nil {
|
||||
return
|
||||
if err := cdc.UnmarshalJSON(genTx, &tx); err != nil {
|
||||
return genesisState, err
|
||||
}
|
||||
msgs := tx.GetMsgs()
|
||||
if len(msgs) != 1 {
|
||||
err = errors.New("must provide genesis StdTx with exactly 1 CreateValidator message")
|
||||
return
|
||||
return genesisState, errors.New(
|
||||
"must provide genesis StdTx with exactly 1 CreateValidator message")
|
||||
}
|
||||
if _, ok := msgs[0].(stake.MsgCreateValidator); !ok {
|
||||
return genesisState, fmt.Errorf(
|
||||
"Genesis transaction %v does not contain a MsgCreateValidator", i)
|
||||
}
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
|
||||
// create the genesis account, give'm few steaks and a buncha token with there name
|
||||
genaccs[i] = genesisAccountFromMsgCreateValidator(msg, freeFermionsAcc)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
||||
}
|
||||
|
||||
// create the final app state
|
||||
genesisState = GenesisState{
|
||||
Accounts: genaccs,
|
||||
StakeData: stakeData,
|
||||
for _, acc := range genesisState.Accounts {
|
||||
// create the genesis account, give'm few steaks and a buncha token with there name
|
||||
for _, coin := range acc.Coins {
|
||||
if coin.Denom == bondDenom {
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.
|
||||
Add(sdk.NewDecFromInt(coin.Amount)) // increase the supply
|
||||
}
|
||||
}
|
||||
}
|
||||
genesisState.StakeData = stakeData
|
||||
genesisState.GenTxs = appGenTxs
|
||||
return genesisState, nil
|
||||
}
|
||||
|
||||
// NewDefaultGenesisState generates the default state for gaia.
|
||||
func NewDefaultGenesisState() GenesisState {
|
||||
return GenesisState{
|
||||
Accounts: nil,
|
||||
StakeData: stake.DefaultGenesisState(),
|
||||
MintData: mint.DefaultGenesisState(),
|
||||
DistrData: distr.DefaultGenesisState(),
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
SlashingData: slashingData,
|
||||
GenTxs: appGenTxs,
|
||||
SlashingData: slashing.DefaultGenesisState(),
|
||||
GenTxs: nil,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func genesisAccountFromMsgCreateValidator(msg stake.MsgCreateValidator, amount sdk.Int) GenesisAccount {
|
||||
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddr))
|
||||
accAuth.Coins = []sdk.Coin{
|
||||
{msg.Description.Moniker + "Token", sdk.NewInt(1000)},
|
||||
{"steak", amount},
|
||||
}
|
||||
return NewGenesisAccount(&accAuth)
|
||||
}
|
||||
|
||||
// GaiaValidateGenesisState ensures that the genesis state obeys the expected invariants
|
||||
|
@ -175,27 +188,43 @@ func validateGenesisStateAccounts(accs []GenesisAccount) (err error) {
|
|||
}
|
||||
|
||||
// GaiaAppGenState but with JSON
|
||||
func GaiaAppGenStateJSON(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
func GaiaAppGenStateJSON(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
appState json.RawMessage, err error) {
|
||||
// create the final app state
|
||||
genesisState, err := GaiaAppGenState(cdc, appGenTxs)
|
||||
genesisState, err := GaiaAppGenState(cdc, genDoc, appGenTxs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appState, err = codec.MarshalJSONIndent(cdc, genesisState)
|
||||
return
|
||||
return codec.MarshalJSONIndent(cdc, genesisState)
|
||||
}
|
||||
|
||||
// CollectStdTxs processes and validates application's genesis StdTxs and returns the list of validators,
|
||||
// appGenTxs, and persistent peers required to generate genesis.json.
|
||||
func CollectStdTxs(moniker string, genTxsDir string, cdc *codec.Codec) (
|
||||
validators []tmtypes.GenesisValidator, appGenTxs []auth.StdTx, persistentPeers string, err error) {
|
||||
// CollectStdTxs processes and validates application's genesis StdTxs and returns
|
||||
// the list of appGenTxs, and persistent peers required to generate genesis.json.
|
||||
func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tmtypes.GenesisDoc) (
|
||||
appGenTxs []auth.StdTx, persistentPeers string, err error) {
|
||||
|
||||
var fos []os.FileInfo
|
||||
fos, err = ioutil.ReadDir(genTxsDir)
|
||||
if err != nil {
|
||||
return
|
||||
return appGenTxs, persistentPeers, err
|
||||
}
|
||||
|
||||
var addresses []string
|
||||
// prepare a map of all accounts in genesis state to then validate
|
||||
// against the validators addresses
|
||||
var appState GenesisState
|
||||
if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
|
||||
return appGenTxs, persistentPeers, err
|
||||
}
|
||||
addrMap := make(map[string]GenesisAccount, len(appState.Accounts))
|
||||
for i := 0; i < len(appState.Accounts); i++ {
|
||||
acc := appState.Accounts[i]
|
||||
strAddr := string(acc.Address)
|
||||
addrMap[strAddr] = acc
|
||||
}
|
||||
|
||||
// addresses and IPs (and port) validator server info
|
||||
var addressesIPs []string
|
||||
|
||||
for _, fo := range fos {
|
||||
filename := filepath.Join(genTxsDir, fo.Name())
|
||||
if !fo.IsDir() && (filepath.Ext(filename) != ".json") {
|
||||
|
@ -204,48 +233,55 @@ func CollectStdTxs(moniker string, genTxsDir string, cdc *codec.Codec) (
|
|||
|
||||
// get the genStdTx
|
||||
var jsonRawTx []byte
|
||||
jsonRawTx, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return
|
||||
if jsonRawTx, err = ioutil.ReadFile(filename); err != nil {
|
||||
return appGenTxs, persistentPeers, err
|
||||
}
|
||||
var genStdTx auth.StdTx
|
||||
err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx)
|
||||
if err != nil {
|
||||
return
|
||||
if err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx); err != nil {
|
||||
return appGenTxs, persistentPeers, err
|
||||
}
|
||||
appGenTxs = append(appGenTxs, genStdTx)
|
||||
|
||||
nodeAddr := genStdTx.GetMemo()
|
||||
if len(nodeAddr) == 0 {
|
||||
err = fmt.Errorf("couldn't find node's address in %s", fo.Name())
|
||||
return
|
||||
// the memo flag is used to store
|
||||
// the ip and node-id, for example this may be:
|
||||
// "528fd3df22b31f4969b05652bfe8f0fe921321d5@192.168.2.37:26656"
|
||||
nodeAddrIP := genStdTx.GetMemo()
|
||||
if len(nodeAddrIP) == 0 {
|
||||
return appGenTxs, persistentPeers, fmt.Errorf(
|
||||
"couldn't find node's address and IP in %s", fo.Name())
|
||||
}
|
||||
|
||||
// genesis transactions must be single-message
|
||||
msgs := genStdTx.GetMsgs()
|
||||
if len(msgs) != 1 {
|
||||
err = errors.New("each genesis transaction must provide a single genesis message")
|
||||
return
|
||||
|
||||
return appGenTxs, persistentPeers, errors.New(
|
||||
"each genesis transaction must provide a single genesis message")
|
||||
}
|
||||
|
||||
// TODO: this could be decoupled from stake.MsgCreateValidator
|
||||
// TODO: and we likely want to do it for real world Gaia
|
||||
// validate the validator address and funds against the accounts in the state
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
validators = append(validators, tmtypes.GenesisValidator{
|
||||
PubKey: msg.PubKey,
|
||||
Power: freeFermionVal,
|
||||
Name: msg.Description.Moniker,
|
||||
})
|
||||
addr := string(sdk.AccAddress(msg.ValidatorAddr))
|
||||
acc, ok := addrMap[addr]
|
||||
if !ok {
|
||||
return appGenTxs, persistentPeers, fmt.Errorf(
|
||||
"account %v not in genesis.json: %+v", addr, addrMap)
|
||||
}
|
||||
if acc.Coins.AmountOf(msg.Delegation.Denom).LT(msg.Delegation.Amount) {
|
||||
err = fmt.Errorf("insufficient fund for the delegation: %s < %s",
|
||||
acc.Coins.AmountOf(msg.Delegation.Denom), msg.Delegation.Amount)
|
||||
}
|
||||
|
||||
// exclude itself from persistent peers
|
||||
if msg.Description.Moniker != moniker {
|
||||
addresses = append(addresses, nodeAddr)
|
||||
addressesIPs = append(addressesIPs, nodeAddrIP)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(addresses)
|
||||
persistentPeers = strings.Join(addresses, ",")
|
||||
sort.Strings(addressesIPs)
|
||||
persistentPeers = strings.Join(addressesIPs, ",")
|
||||
|
||||
return
|
||||
return appGenTxs, persistentPeers, nil
|
||||
}
|
||||
|
||||
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -27,7 +30,8 @@ var (
|
|||
|
||||
func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
|
||||
// start with the default staking genesis state
|
||||
stakeData := stake.DefaultGenesisState()
|
||||
appState := NewDefaultGenesisState()
|
||||
stakeData := appState.StakeData
|
||||
genAccs := make([]GenesisAccount, len(genTxs))
|
||||
|
||||
for i, genTx := range genTxs {
|
||||
|
@ -35,17 +39,15 @@ func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
|
|||
require.Equal(t, 1, len(msgs))
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
|
||||
// get genesis flag account information
|
||||
genAccs[i] = genesisAccountFromMsgCreateValidator(msg, freeFermionsAcc)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
||||
acc := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddr))
|
||||
acc.Coins = sdk.Coins{sdk.NewInt64Coin(bondDenom, 150)}
|
||||
genAccs[i] = NewGenesisAccount(&acc)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(150)) // increase the supply
|
||||
}
|
||||
|
||||
// create the final app state
|
||||
return GenesisState{
|
||||
Accounts: genAccs,
|
||||
StakeData: stakeData,
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
}
|
||||
appState.Accounts = genAccs
|
||||
return appState
|
||||
}
|
||||
|
||||
func TestToAccount(t *testing.T) {
|
||||
|
@ -68,6 +70,19 @@ func TestGaiaAppGenTx(t *testing.T) {
|
|||
func TestGaiaAppGenState(t *testing.T) {
|
||||
cdc := MakeCodec()
|
||||
_ = cdc
|
||||
var genDoc tmtypes.GenesisDoc
|
||||
|
||||
// test unmarshalling error
|
||||
_, err := GaiaAppGenState(cdc, genDoc, []json.RawMessage{})
|
||||
require.Error(t, err)
|
||||
|
||||
appState := makeGenesisState(t, []auth.StdTx{})
|
||||
genDoc.AppState, err = json.Marshal(appState)
|
||||
require.NoError(t, err)
|
||||
|
||||
// test validation error
|
||||
_, err = GaiaAppGenState(cdc, genDoc, []json.RawMessage{})
|
||||
require.Error(t, err)
|
||||
|
||||
// TODO test must provide at least genesis transaction
|
||||
// TODO test with both one and two genesis transactions:
|
||||
|
@ -77,7 +92,10 @@ func TestGaiaAppGenState(t *testing.T) {
|
|||
func makeMsg(name string, pk crypto.PubKey) auth.StdTx {
|
||||
desc := stake.NewDescription(name, "", "", "")
|
||||
comm := stakeTypes.CommissionMsg{}
|
||||
msg := stake.NewMsgCreateValidator(sdk.ValAddress(pk.Address()), pk, sdk.NewInt64Coin("steak", 50), desc, comm)
|
||||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(pk.Address()), pk,
|
||||
sdk.NewInt64Coin(bondDenom, 50), desc, comm,
|
||||
)
|
||||
return auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, nil, "")
|
||||
}
|
||||
|
||||
|
@ -106,3 +124,10 @@ func TestGaiaGenesisValidation(t *testing.T) {
|
|||
err = GaiaValidateGenesisState(genesisState)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestNewDefaultGenesisAccount(t *testing.T) {
|
||||
addr := secp256k1.GenPrivKeySecp256k1([]byte("")).PubKey().Address()
|
||||
acc := NewDefaultGenesisAccount(sdk.AccAddress(addr))
|
||||
require.Equal(t, sdk.NewInt(1000), acc.Coins.AmountOf("fooToken"))
|
||||
require.Equal(t, sdk.NewInt(150), acc.Coins.AmountOf(bondDenom))
|
||||
}
|
||||
|
|
|
@ -4,12 +4,15 @@ import (
|
|||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
|
@ -49,42 +52,93 @@ func init() {
|
|||
func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||
var genesisAccounts []GenesisAccount
|
||||
|
||||
amt := int64(10000)
|
||||
amount := int64(r.Intn(1e6))
|
||||
numInitiallyBonded := int64(r.Intn(250))
|
||||
numAccs := int64(len(accs))
|
||||
if numInitiallyBonded > numAccs {
|
||||
numInitiallyBonded = numAccs
|
||||
}
|
||||
fmt.Printf("Selected randomly generated parameters for simulated genesis: {amount of steak per account: %v, initially bonded validators: %v}\n", amount, numInitiallyBonded)
|
||||
|
||||
// Randomly generate some genesis accounts
|
||||
for _, acc := range accs {
|
||||
coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(amt)}}
|
||||
coins := sdk.Coins{sdk.Coin{"steak", sdk.NewInt(amount)}}
|
||||
genesisAccounts = append(genesisAccounts, GenesisAccount{
|
||||
Address: acc.Address,
|
||||
Coins: coins,
|
||||
})
|
||||
}
|
||||
|
||||
// Default genesis state
|
||||
govGenesis := gov.DefaultGenesisState()
|
||||
stakeGenesis := stake.DefaultGenesisState()
|
||||
slashingGenesis := slashing.DefaultGenesisState()
|
||||
// Random genesis states
|
||||
govGenesis := gov.GenesisState{
|
||||
StartingProposalID: uint64(r.Intn(100)),
|
||||
DepositParams: gov.DepositParams{
|
||||
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", int64(r.Intn(1e3)))},
|
||||
MaxDepositPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
|
||||
},
|
||||
VotingParams: gov.VotingParams{
|
||||
VotingPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
|
||||
},
|
||||
TallyParams: gov.TallyParams{
|
||||
Threshold: sdk.NewDecWithPrec(5, 1),
|
||||
Veto: sdk.NewDecWithPrec(334, 3),
|
||||
GovernancePenalty: sdk.NewDecWithPrec(1, 2),
|
||||
},
|
||||
}
|
||||
fmt.Printf("Selected randomly generated governance parameters: %+v\n", govGenesis)
|
||||
stakeGenesis := stake.GenesisState{
|
||||
Pool: stake.InitialPool(),
|
||||
Params: stake.Params{
|
||||
UnbondingTime: time.Duration(r.Intn(60*60*24*3*2)) * time.Second,
|
||||
MaxValidators: uint16(r.Intn(250)),
|
||||
BondDenom: "steak",
|
||||
},
|
||||
}
|
||||
fmt.Printf("Selected randomly generated staking parameters: %+v\n", stakeGenesis)
|
||||
slashingGenesis := slashing.GenesisState{
|
||||
Params: slashing.Params{
|
||||
MaxEvidenceAge: stakeGenesis.Params.UnbondingTime,
|
||||
DoubleSignUnbondDuration: time.Duration(r.Intn(60*60*24)) * time.Second,
|
||||
SignedBlocksWindow: int64(r.Intn(1000)),
|
||||
DowntimeUnbondDuration: time.Duration(r.Intn(86400)) * time.Second,
|
||||
MinSignedPerWindow: sdk.NewDecWithPrec(int64(r.Intn(10)), 1),
|
||||
SlashFractionDoubleSign: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(50) + 1))),
|
||||
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(200) + 1))),
|
||||
},
|
||||
}
|
||||
fmt.Printf("Selected randomly generated slashing parameters: %+v\n", slashingGenesis)
|
||||
mintGenesis := mint.GenesisState{
|
||||
Minter: mint.Minter{
|
||||
InflationLastTime: time.Unix(0, 0),
|
||||
Inflation: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
||||
},
|
||||
Params: mint.Params{
|
||||
MintDenom: "steak",
|
||||
InflationRateChange: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
||||
InflationMax: sdk.NewDecWithPrec(20, 2),
|
||||
InflationMin: sdk.NewDecWithPrec(7, 2),
|
||||
GoalBonded: sdk.NewDecWithPrec(67, 2),
|
||||
},
|
||||
}
|
||||
fmt.Printf("Selected randomly generated minting parameters: %v\n", mintGenesis)
|
||||
var validators []stake.Validator
|
||||
var delegations []stake.Delegation
|
||||
|
||||
// XXX Try different numbers of initially bonded validators
|
||||
numInitiallyBonded := int64(50)
|
||||
valAddrs := make([]sdk.ValAddress, numInitiallyBonded)
|
||||
for i := 0; i < int(numInitiallyBonded); i++ {
|
||||
valAddr := sdk.ValAddress(accs[i].Address)
|
||||
valAddrs[i] = valAddr
|
||||
|
||||
validator := stake.NewValidator(valAddr, accs[i].PubKey, stake.Description{})
|
||||
validator.Tokens = sdk.NewDec(amt)
|
||||
validator.DelegatorShares = sdk.NewDec(amt)
|
||||
delegation := stake.Delegation{accs[i].Address, valAddr, sdk.NewDec(amt), 0}
|
||||
validator.Tokens = sdk.NewDec(amount)
|
||||
validator.DelegatorShares = sdk.NewDec(amount)
|
||||
delegation := stake.Delegation{accs[i].Address, valAddr, sdk.NewDec(amount), 0}
|
||||
validators = append(validators, validator)
|
||||
delegations = append(delegations, delegation)
|
||||
}
|
||||
stakeGenesis.Pool.LooseTokens = sdk.NewDec(amt*250 + (numInitiallyBonded * amt))
|
||||
stakeGenesis.Pool.LooseTokens = sdk.NewDec((amount * numAccs) + (numInitiallyBonded * amount))
|
||||
stakeGenesis.Validators = validators
|
||||
stakeGenesis.Bonds = delegations
|
||||
mintGenesis := mint.DefaultGenesisState()
|
||||
|
||||
genesis := GenesisState{
|
||||
Accounts: genesisAccounts,
|
||||
|
@ -113,7 +167,7 @@ func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
|
|||
{50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)},
|
||||
{50, distrsim.SimulateMsgWithdrawValidatorRewardsAll(app.accountKeeper, app.distrKeeper)},
|
||||
{5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper)},
|
||||
{100, govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper)},
|
||||
{100, govsim.SimulateMsgDeposit(app.govKeeper)},
|
||||
{100, stakesim.SimulateMsgCreateValidator(app.accountKeeper, app.stakeKeeper)},
|
||||
{5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)},
|
||||
{100, stakesim.SimulateMsgDelegate(app.accountKeeper, app.stakeKeeper)},
|
||||
|
@ -141,7 +195,7 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
|
|||
var logger log.Logger
|
||||
logger = log.NewNopLogger()
|
||||
var db dbm.DB
|
||||
dir := os.TempDir()
|
||||
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
|
||||
db, _ = dbm.NewGoLevelDB("Simulation", dir)
|
||||
defer func() {
|
||||
db.Close()
|
||||
|
@ -183,7 +237,13 @@ func TestFullGaiaSimulation(t *testing.T) {
|
|||
} else {
|
||||
logger = log.NewNopLogger()
|
||||
}
|
||||
db := dbm.NewMemDB()
|
||||
var db dbm.DB
|
||||
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
|
||||
db, _ = dbm.NewGoLevelDB("Simulation", dir)
|
||||
defer func() {
|
||||
db.Close()
|
||||
os.RemoveAll(dir)
|
||||
}()
|
||||
app := NewGaiaApp(logger, db, nil)
|
||||
require.Equal(t, "GaiaApp", app.Name())
|
||||
|
||||
|
@ -198,11 +258,112 @@ func TestFullGaiaSimulation(t *testing.T) {
|
|||
commit,
|
||||
)
|
||||
if commit {
|
||||
fmt.Println("Database Size", db.Stats()["database.size"])
|
||||
// for memdb:
|
||||
// fmt.Println("Database Size", db.Stats()["database.size"])
|
||||
fmt.Println("GoLevelDB Stats")
|
||||
fmt.Println(db.Stats()["leveldb.stats"])
|
||||
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
|
||||
}
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestGaiaImportExport(t *testing.T) {
|
||||
if !enabled {
|
||||
t.Skip("Skipping Gaia import/export simulation")
|
||||
}
|
||||
|
||||
// Setup Gaia application
|
||||
var logger log.Logger
|
||||
if verbose {
|
||||
logger = log.TestingLogger()
|
||||
} else {
|
||||
logger = log.NewNopLogger()
|
||||
}
|
||||
var db dbm.DB
|
||||
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
|
||||
db, _ = dbm.NewGoLevelDB("Simulation", dir)
|
||||
defer func() {
|
||||
db.Close()
|
||||
os.RemoveAll(dir)
|
||||
}()
|
||||
app := NewGaiaApp(logger, db, nil)
|
||||
require.Equal(t, "GaiaApp", app.Name())
|
||||
|
||||
// Run randomized simulation
|
||||
err := simulation.SimulateFromSeed(
|
||||
t, app.BaseApp, appStateFn, seed,
|
||||
testAndRunTxs(app),
|
||||
[]simulation.RandSetup{},
|
||||
invariants(app),
|
||||
numBlocks,
|
||||
blockSize,
|
||||
commit,
|
||||
)
|
||||
if commit {
|
||||
// for memdb:
|
||||
// fmt.Println("Database Size", db.Stats()["database.size"])
|
||||
fmt.Println("GoLevelDB Stats")
|
||||
fmt.Println(db.Stats()["leveldb.stats"])
|
||||
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
|
||||
}
|
||||
require.Nil(t, err)
|
||||
|
||||
fmt.Printf("Exporting genesis...\n")
|
||||
|
||||
appState, _, err := app.ExportAppStateAndValidators()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Importing genesis...\n")
|
||||
|
||||
newDir, _ := ioutil.TempDir("", "goleveldb-gaia-sim-2")
|
||||
newDB, _ := dbm.NewGoLevelDB("Simulation-2", dir)
|
||||
defer func() {
|
||||
newDB.Close()
|
||||
os.RemoveAll(newDir)
|
||||
}()
|
||||
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil)
|
||||
require.Equal(t, "GaiaApp", newApp.Name())
|
||||
request := abci.RequestInitChain{
|
||||
AppStateBytes: appState,
|
||||
}
|
||||
newApp.InitChain(request)
|
||||
newApp.Commit()
|
||||
|
||||
fmt.Printf("Comparing stores...\n")
|
||||
ctxA := app.NewContext(true, abci.Header{})
|
||||
ctxB := newApp.NewContext(true, abci.Header{})
|
||||
type StoreKeysPrefixes struct {
|
||||
A sdk.StoreKey
|
||||
B sdk.StoreKey
|
||||
Prefixes [][]byte
|
||||
}
|
||||
storeKeysPrefixes := []StoreKeysPrefixes{
|
||||
{app.keyMain, newApp.keyMain, [][]byte{}},
|
||||
{app.keyAccount, newApp.keyAccount, [][]byte{}},
|
||||
{app.keyStake, newApp.keyStake, [][]byte{stake.UnbondingQueueKey, stake.RedelegationQueueKey, stake.ValidatorQueueKey}}, // ordering may change but it doesn't matter
|
||||
{app.keySlashing, newApp.keySlashing, [][]byte{}},
|
||||
{app.keyMint, newApp.keyMint, [][]byte{}},
|
||||
{app.keyDistr, newApp.keyDistr, [][]byte{}},
|
||||
{app.keyFeeCollection, newApp.keyFeeCollection, [][]byte{}},
|
||||
{app.keyParams, newApp.keyParams, [][]byte{}},
|
||||
{app.keyGov, newApp.keyGov, [][]byte{}},
|
||||
}
|
||||
for _, storeKeysPrefix := range storeKeysPrefixes {
|
||||
storeKeyA := storeKeysPrefix.A
|
||||
storeKeyB := storeKeysPrefix.B
|
||||
prefixes := storeKeysPrefix.Prefixes
|
||||
storeA := ctxA.KVStore(storeKeyA)
|
||||
storeB := ctxB.KVStore(storeKeyB)
|
||||
kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB, prefixes)
|
||||
fmt.Printf("Compared %d key/value pairs between %s and %s\n", count, storeKeyA, storeKeyB)
|
||||
require.True(t, equal, "unequal stores: %s / %s:\nstore A %s (%X) => %s (%X)\nstore B %s (%X) => %s (%X)",
|
||||
storeKeyA, storeKeyB, kvA.Key, kvA.Key, kvA.Value, kvA.Value, kvB.Key, kvB.Key, kvB.Value, kvB.Value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
||||
// and doesn't depend on gaia
|
||||
func TestAppStateDeterminism(t *testing.T) {
|
||||
|
|
|
@ -8,8 +8,11 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
@ -207,7 +210,7 @@ func TestGaiaCLIGasAuto(t *testing.T) {
|
|||
|
||||
func TestGaiaCLICreateValidator(t *testing.T) {
|
||||
chainID, servAddr, port := initializeFixtures(t)
|
||||
flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
|
||||
flags := fmt.Sprintf("--home=%s --chain-id=%v --node=%s", gaiacliHome, chainID, servAddr)
|
||||
|
||||
// start gaiad server
|
||||
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr))
|
||||
|
@ -285,6 +288,12 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
validator = executeGetValidator(t, fmt.Sprintf("gaiacli query validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
|
||||
require.Equal(t, "1.0000000000", validator.Tokens.String())
|
||||
|
||||
validatorUbds := executeGetValidatorUnbondingDelegations(t,
|
||||
fmt.Sprintf("gaiacli query unbonding-delegations-from %s --output=json %v",
|
||||
sdk.ValAddress(barAddr), flags))
|
||||
require.Len(t, validatorUbds, 1)
|
||||
require.Equal(t, "1", validatorUbds[0].Balance.Amount.String())
|
||||
|
||||
params := executeGetParams(t, fmt.Sprintf("gaiacli query parameters --output=json %v", flags))
|
||||
require.True(t, defaultParams.Equal(params))
|
||||
|
||||
|
@ -340,7 +349,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
|
||||
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
|
||||
require.Equal(t, int64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, uint64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
|
||||
|
||||
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
|
||||
|
@ -383,7 +392,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
|
||||
require.Equal(t, int64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, uint64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
|
||||
|
||||
voteStr := fmt.Sprintf("gaiacli tx vote %v", flags)
|
||||
|
@ -405,12 +414,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
vote := executeGetVote(t, fmt.Sprintf("gaiacli query vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags))
|
||||
require.Equal(t, int64(1), vote.ProposalID)
|
||||
require.Equal(t, uint64(1), vote.ProposalID)
|
||||
require.Equal(t, gov.OptionYes, vote.Option)
|
||||
|
||||
votes := executeGetVotes(t, fmt.Sprintf("gaiacli query votes --proposal-id=1 --output=json %v", flags))
|
||||
require.Len(t, votes, 1)
|
||||
require.Equal(t, int64(1), votes[0].ProposalID)
|
||||
require.Equal(t, uint64(1), votes[0].ProposalID)
|
||||
require.Equal(t, gov.OptionYes, votes[0].Option)
|
||||
|
||||
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=DepositPeriod %v", flags), "")
|
||||
|
@ -430,7 +439,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
executeWrite(t, spStr, app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --latest=1 %v", flags), "")
|
||||
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --limit=1 %v", flags), "")
|
||||
require.Equal(t, " 2 - Apples", proposalsQuery)
|
||||
}
|
||||
|
||||
|
@ -439,7 +448,8 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
|
||||
|
||||
// start gaiad server
|
||||
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr))
|
||||
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf(
|
||||
"gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr))
|
||||
|
||||
defer proc.Stop(false)
|
||||
tests.WaitForTMStart(port)
|
||||
|
@ -484,11 +494,11 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
unsignedTxFile := writeToNewTempFile(t, stdout)
|
||||
defer os.Remove(unsignedTxFile.Name())
|
||||
|
||||
// Test sign --print-sigs
|
||||
// Test sign --validate-signatures
|
||||
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
"gaiacli tx sign %v --print-sigs %v", flags, unsignedTxFile.Name()))
|
||||
require.True(t, success)
|
||||
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n", fooAddr.String()), stdout)
|
||||
"gaiacli tx sign %v --validate-signatures %v", flags, unsignedTxFile.Name()))
|
||||
require.False(t, success)
|
||||
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n\n", fooAddr.String()), stdout)
|
||||
|
||||
// Test sign
|
||||
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
|
@ -505,15 +515,17 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
|
||||
// Test sign --print-signatures
|
||||
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
"gaiacli tx sign %v --print-sigs %v", flags, signedTxFile.Name()))
|
||||
"gaiacli tx sign %v --validate-signatures %v", flags, signedTxFile.Name()))
|
||||
require.True(t, success)
|
||||
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n 0: %v\n", fooAddr.String(), fooAddr.String()), stdout)
|
||||
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n 0: %v\t[OK]\n\n", fooAddr.String(),
|
||||
fooAddr.String()), stdout)
|
||||
|
||||
// Test broadcast
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
|
||||
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli tx broadcast %v --json %v", flags, signedTxFile.Name()))
|
||||
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
"gaiacli tx broadcast %v --json %v", flags, signedTxFile.Name()))
|
||||
require.True(t, success)
|
||||
var result struct {
|
||||
Response abci.ResponseDeliverTx
|
||||
|
@ -535,7 +547,7 @@ func TestGaiaCLIConfig(t *testing.T) {
|
|||
servAddr, port, err := server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
node := fmt.Sprintf("%s:%s", servAddr, port)
|
||||
chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome))
|
||||
chainID := executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome))
|
||||
executeWrite(t, fmt.Sprintf("gaiacli --home=%s config", gaiadHome), gaiacliHome, node, "y")
|
||||
config, err := ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml"))
|
||||
require.NoError(t, err)
|
||||
|
@ -585,12 +597,27 @@ func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
|
|||
tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe-reset-all", gaiadHome), "")
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
||||
|
||||
chainID = executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome))
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
||||
|
||||
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf(
|
||||
"gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||
chainID = executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome))
|
||||
genFile := filepath.Join(gaiadHome, "config", "genesis.json")
|
||||
genDoc := readGenesisFile(t, genFile)
|
||||
var appState app.GenesisState
|
||||
err := codec.Cdc.UnmarshalJSON(genDoc.AppState, &appState)
|
||||
require.NoError(t, err)
|
||||
appState.Accounts = []app.GenesisAccount{app.NewDefaultGenesisAccount(fooAddr)}
|
||||
appStateJSON, err := codec.Cdc.MarshalJSON(appState)
|
||||
require.NoError(t, err)
|
||||
genDoc.AppState = appStateJSON
|
||||
genDoc.SaveAs(genFile)
|
||||
executeWrite(t, fmt.Sprintf(
|
||||
"gaiad gentx --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome),
|
||||
app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiad collect-gentxs --home=%s", gaiadHome), app.DefaultKeyPass)
|
||||
// get a free port, also setup some common flags
|
||||
servAddr, port, err := server.FreeTCPAddr()
|
||||
servAddr, port, err = server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
return
|
||||
}
|
||||
|
@ -609,6 +636,18 @@ func writeToNewTempFile(t *testing.T, s string) *os.File {
|
|||
return fp
|
||||
}
|
||||
|
||||
func readGenesisFile(t *testing.T, genFile string) types.GenesisDoc {
|
||||
var genDoc types.GenesisDoc
|
||||
fp, err := os.Open(genFile)
|
||||
require.NoError(t, err)
|
||||
fileContents, err := ioutil.ReadAll(fp)
|
||||
require.NoError(t, err)
|
||||
defer fp.Close()
|
||||
err = codec.Cdc.UnmarshalJSON(fileContents, &genDoc)
|
||||
require.NoError(t, err)
|
||||
return genDoc
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// executors
|
||||
|
||||
|
@ -693,6 +732,24 @@ func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
|||
return validator
|
||||
}
|
||||
|
||||
func executeGetValidatorUnbondingDelegations(t *testing.T, cmdStr string) []stake.UnbondingDelegation {
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var ubds []stake.UnbondingDelegation
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &ubds)
|
||||
require.NoError(t, err, "out %v\n, err %v", out, err)
|
||||
return ubds
|
||||
}
|
||||
|
||||
func executeGetValidatorRedelegations(t *testing.T, cmdStr string) []stake.Redelegation {
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var reds []stake.Redelegation
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &reds)
|
||||
require.NoError(t, err, "out %v\n, err %v", out, err)
|
||||
return reds
|
||||
}
|
||||
|
||||
func executeGetPool(t *testing.T, cmdStr string) stake.Pool {
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var pool stake.Pool
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
|
@ -28,10 +29,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
storeAcc = "acc"
|
||||
storeGov = "gov"
|
||||
storeSlashing = "slashing"
|
||||
storeStake = "stake"
|
||||
storeAcc = "acc"
|
||||
storeGov = "gov"
|
||||
storeSlashing = "slashing"
|
||||
storeStake = "stake"
|
||||
queryRouteStake = "stake"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
|
@ -46,6 +48,12 @@ func main() {
|
|||
cobra.EnableCommandSorting = false
|
||||
cdc := app.MakeCodec()
|
||||
|
||||
config := sdk.GetConfig()
|
||||
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
||||
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
|
||||
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
|
||||
config.Seal()
|
||||
|
||||
// TODO: setup keybase, viper object, etc. to be passed into
|
||||
// the below functions and eliminate global vars, like we do
|
||||
// with the cdc
|
||||
|
@ -70,21 +78,23 @@ func main() {
|
|||
authcmd.GetAccountCmd(storeAcc, cdc, authcmd.GetAccountDecoder(cdc)),
|
||||
stakecmd.GetCmdQueryDelegation(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryDelegations(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegation(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegations(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryRedelegation(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryRedelegations(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryValidator(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryValidators(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryValidatorUnbondingDelegations(queryRouteStake, cdc),
|
||||
stakecmd.GetCmdQueryValidatorRedelegations(queryRouteStake, cdc),
|
||||
stakecmd.GetCmdQueryParams(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryPool(storeStake, cdc),
|
||||
govcmd.GetCmdQueryProposal(storeGov, cdc),
|
||||
govcmd.GetCmdQueryProposals(storeGov, cdc),
|
||||
govcmd.GetCmdQueryDeposit(storeGov, cdc),
|
||||
govcmd.GetCmdQueryDeposits(storeGov, cdc),
|
||||
stakecmd.GetCmdQueryRedelegation(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryRedelegations(storeStake, cdc),
|
||||
slashingcmd.GetCmdQuerySigningInfo(storeSlashing, cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegation(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegations(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryValidator(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryValidators(storeStake, cdc),
|
||||
govcmd.GetCmdQueryVote(storeGov, cdc),
|
||||
govcmd.GetCmdQueryVotes(storeGov, cdc),
|
||||
govcmd.GetCmdQueryDeposit(storeGov, cdc),
|
||||
govcmd.GetCmdQueryDeposits(storeGov, cdc),
|
||||
slashingcmd.GetCmdQuerySigningInfo(storeSlashing, cdc),
|
||||
)...)
|
||||
|
||||
//Add query commands
|
||||
|
|
|
@ -18,10 +18,18 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cdc := app.MakeCodec()
|
||||
|
||||
config := sdk.GetConfig()
|
||||
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
||||
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
|
||||
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
|
||||
config.Seal()
|
||||
|
||||
ctx := server.NewDefaultContext()
|
||||
cobra.EnableCommandSorting = false
|
||||
rootCmd := &cobra.Command{
|
||||
|
@ -31,7 +39,8 @@ func main() {
|
|||
}
|
||||
appInit := app.GaiaAppInit()
|
||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.CollectGenTxsCmd(ctx, cdc))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, server.AppInit{}))
|
||||
rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
|
|
|
@ -19,6 +19,13 @@ import (
|
|||
)
|
||||
|
||||
func init() {
|
||||
|
||||
config := sdk.GetConfig()
|
||||
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
||||
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
|
||||
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
|
||||
config.Seal()
|
||||
|
||||
rootCmd.AddCommand(txCmd)
|
||||
rootCmd.AddCommand(pubkeyCmd)
|
||||
rootCmd.AddCommand(addrCmd)
|
||||
|
@ -213,7 +220,7 @@ func runTxCmd(cmd *cobra.Command, args []string) error {
|
|||
var tx = auth.StdTx{}
|
||||
cdc := gaia.MakeCodec()
|
||||
|
||||
err = cdc.UnmarshalBinary(txBytes, &tx)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
type initConfig struct {
|
||||
ChainID string
|
||||
GenTxsDir string
|
||||
Name string
|
||||
NodeID string
|
||||
ValPubKey crypto.PubKey
|
||||
}
|
||||
|
||||
// nolint
|
||||
func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "collect-gentxs",
|
||||
Short: "Collect genesis txs and output a genesis.json file",
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
name := viper.GetString(client.FlagName)
|
||||
|
||||
nodeID, valPubKey, err := InitializeNodeValidatorFiles(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genDoc, err := loadGenesisDoc(cdc, config.GenesisFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toPrint := printInfo{
|
||||
Moniker: config.Moniker,
|
||||
ChainID: genDoc.ChainID,
|
||||
NodeID: nodeID,
|
||||
}
|
||||
|
||||
initCfg := initConfig{
|
||||
ChainID: genDoc.ChainID,
|
||||
GenTxsDir: filepath.Join(config.RootDir, "config", "gentx"),
|
||||
Name: name,
|
||||
NodeID: nodeID,
|
||||
ValPubKey: valPubKey,
|
||||
}
|
||||
|
||||
appMessage, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toPrint.AppMessage = appMessage
|
||||
|
||||
// print out some key information
|
||||
return displayInfo(cdc, toPrint)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func genAppStateFromConfig(
|
||||
cdc *codec.Codec, config *cfg.Config, initCfg initConfig, genDoc types.GenesisDoc,
|
||||
) (appState json.RawMessage, err error) {
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
var (
|
||||
appGenTxs []auth.StdTx
|
||||
persistentPeers string
|
||||
genTxs []json.RawMessage
|
||||
jsonRawTx json.RawMessage
|
||||
)
|
||||
|
||||
// process genesis transactions, else create default genesis.json
|
||||
appGenTxs, persistentPeers, err = app.CollectStdTxs(
|
||||
cdc, config.Moniker, initCfg.GenTxsDir, genDoc,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
genTxs = make([]json.RawMessage, len(appGenTxs))
|
||||
config.P2P.PersistentPeers = persistentPeers
|
||||
|
||||
for i, stdTx := range appGenTxs {
|
||||
jsonRawTx, err = cdc.MarshalJSON(stdTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs[i] = jsonRawTx
|
||||
}
|
||||
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
|
||||
appState, err = app.GaiaAppGenStateJSON(cdc, genDoc, genTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = ExportGenesisFile(genFile, initCfg.ChainID, nil, appState)
|
||||
return
|
||||
}
|
|
@ -55,9 +55,20 @@ following delegation and commission default parameters:
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genDoc, err := loadGenesisDoc(cdc, config.GenesisFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read --pubkey, if empty take it from priv_validator.json
|
||||
if valPubKeyString := viper.GetString(cli.FlagPubKey); valPubKeyString != "" {
|
||||
valPubKey, err = sdk.GetConsPubKeyBech32(valPubKeyString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Run gaiad tx create-validator
|
||||
prepareFlagsForTxCreateValidator(config, nodeID, ip, valPubKey)
|
||||
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey)
|
||||
createValidatorCmd := cli.GetCmdCreateValidator(cdc)
|
||||
|
||||
w, err := ioutil.TempFile("", "gentx")
|
||||
|
@ -82,28 +93,41 @@ following delegation and commission default parameters:
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(tmcli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id")
|
||||
cmd.Flags().String(client.FlagName, "", "name of private key with which to sign the gentx")
|
||||
cmd.Flags().AddFlagSet(cli.FsCommissionCreate)
|
||||
cmd.Flags().AddFlagSet(cli.FsAmount)
|
||||
cmd.Flags().AddFlagSet(cli.FsPk)
|
||||
cmd.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip string, valPubKey crypto.PubKey) {
|
||||
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome)) // --home
|
||||
func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip, chainID string,
|
||||
valPubKey crypto.PubKey) {
|
||||
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome)) // --home
|
||||
viper.Set(client.FlagChainID, chainID)
|
||||
viper.Set(client.FlagFrom, viper.GetString(client.FlagName)) // --from
|
||||
viper.Set(cli.FlagNodeID, nodeID) // --node-id
|
||||
viper.Set(cli.FlagIP, ip) // --ip
|
||||
viper.Set(cli.FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey)) // --pubkey
|
||||
viper.Set(cli.FlagAmount, defaultAmount) // --amount
|
||||
viper.Set(cli.FlagCommissionRate, defaultCommissionRate)
|
||||
viper.Set(cli.FlagCommissionMaxRate, defaultCommissionMaxRate)
|
||||
viper.Set(cli.FlagCommissionMaxChangeRate, defaultCommissionMaxChangeRate)
|
||||
viper.Set(cli.FlagGenesisFormat, true) // --genesis-format
|
||||
viper.Set(cli.FlagMoniker, config.Moniker) // --moniker
|
||||
viper.Set(cli.FlagGenesisFormat, true) // --genesis-format
|
||||
viper.Set(cli.FlagMoniker, config.Moniker) // --moniker
|
||||
if config.Moniker == "" {
|
||||
viper.Set(cli.FlagMoniker, viper.GetString(client.FlagName))
|
||||
}
|
||||
if viper.GetString(cli.FlagAmount) == "" {
|
||||
viper.Set(cli.FlagAmount, defaultAmount)
|
||||
}
|
||||
if viper.GetString(cli.FlagCommissionRate) == "" {
|
||||
viper.Set(cli.FlagCommissionRate, defaultCommissionRate)
|
||||
}
|
||||
if viper.GetString(cli.FlagCommissionMaxRate) == "" {
|
||||
viper.Set(cli.FlagCommissionMaxRate, defaultCommissionMaxRate)
|
||||
}
|
||||
if viper.GetString(cli.FlagCommissionMaxChangeRate) == "" {
|
||||
viper.Set(cli.FlagCommissionMaxChangeRate, defaultCommissionMaxChangeRate)
|
||||
}
|
||||
}
|
||||
|
||||
func prepareFlagsForTxSign() {
|
||||
|
|
|
@ -2,51 +2,27 @@ package init
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
const (
|
||||
flagWithTxs = "with-txs"
|
||||
flagOverwrite = "overwrite"
|
||||
flagClientHome = "home-client"
|
||||
flagOverwriteKey = "overwrite-key"
|
||||
flagSkipGenesis = "skip-genesis"
|
||||
flagMoniker = "moniker"
|
||||
flagOverwrite = "overwrite"
|
||||
flagClientHome = "home-client"
|
||||
flagMoniker = "moniker"
|
||||
)
|
||||
|
||||
type initConfig struct {
|
||||
ChainID string
|
||||
GenTxsDir string
|
||||
Name string
|
||||
NodeID string
|
||||
ClientHome string
|
||||
WithTxs bool
|
||||
Overwrite bool
|
||||
OverwriteKey bool
|
||||
ValPubKey crypto.PubKey
|
||||
}
|
||||
|
||||
type printInfo struct {
|
||||
Moniker string `json:"moniker"`
|
||||
ChainID string `json:"chain_id"`
|
||||
|
@ -70,22 +46,16 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize private validator, p2p, genesis, and application configuration files",
|
||||
Long: `Initialize validators's and node's configuration files.
|
||||
|
||||
Note that only node's configuration files will be written if the flag --skip-genesis is
|
||||
enabled, and the genesis file will not be generated.
|
||||
`,
|
||||
Args: cobra.NoArgs,
|
||||
Long: `Initialize validators's and node's configuration files.`,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
|
||||
name := viper.GetString(client.FlagName)
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
if chainID == "" {
|
||||
chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
|
||||
}
|
||||
nodeID, valPubKey, err := InitializeNodeValidatorFiles(config)
|
||||
nodeID, _, err := InitializeNodeValidatorFiles(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -93,37 +63,26 @@ enabled, and the genesis file will not be generated.
|
|||
if viper.GetString(flagMoniker) != "" {
|
||||
config.Moniker = viper.GetString(flagMoniker)
|
||||
}
|
||||
if config.Moniker == "" && name != "" {
|
||||
config.Moniker = name
|
||||
}
|
||||
toPrint := printInfo{
|
||||
ChainID: chainID,
|
||||
Moniker: config.Moniker,
|
||||
NodeID: nodeID,
|
||||
}
|
||||
if viper.GetBool(flagSkipGenesis) {
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
return displayInfo(cdc, toPrint)
|
||||
}
|
||||
|
||||
initCfg := initConfig{
|
||||
ChainID: chainID,
|
||||
GenTxsDir: filepath.Join(config.RootDir, "config", "gentx"),
|
||||
Name: name,
|
||||
NodeID: nodeID,
|
||||
ClientHome: viper.GetString(flagClientHome),
|
||||
WithTxs: viper.GetBool(flagWithTxs),
|
||||
Overwrite: viper.GetBool(flagOverwrite),
|
||||
OverwriteKey: viper.GetBool(flagOverwriteKey),
|
||||
ValPubKey: valPubKey,
|
||||
var appState json.RawMessage
|
||||
genFile := config.GenesisFile()
|
||||
if appState, err = initializeEmptyGenesis(cdc, genFile, chainID,
|
||||
viper.GetBool(flagOverwrite)); err != nil {
|
||||
return err
|
||||
}
|
||||
appMessage, err := initWithConfig(cdc, config, initCfg)
|
||||
// print out some key information
|
||||
if err != nil {
|
||||
if err = ExportGenesisFile(genFile, chainID, nil, appState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toPrint.AppMessage = appMessage
|
||||
toPrint := printInfo{
|
||||
ChainID: chainID,
|
||||
Moniker: config.Moniker,
|
||||
NodeID: nodeID,
|
||||
AppMessage: appState,
|
||||
}
|
||||
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
|
||||
return displayInfo(cdc, toPrint)
|
||||
},
|
||||
}
|
||||
|
@ -131,151 +90,6 @@ enabled, and the genesis file will not be generated.
|
|||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file")
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().Bool(flagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/")
|
||||
cmd.Flags().String(client.FlagName, "", "name of private key with which to sign the gentx")
|
||||
cmd.Flags().String(flagMoniker, "", "overrides --name flag and set the validator's moniker to a different value; ignored if it runs without the --with-txs flag")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
|
||||
cmd.Flags().Bool(flagOverwriteKey, false, "overwrite client's key")
|
||||
cmd.Flags().Bool(flagSkipGenesis, false, "do not create genesis.json")
|
||||
cmd.Flags().String(flagMoniker, "", "set the validator's moniker")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
|
||||
func InitializeNodeValidatorFiles(config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error) {
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nodeID = string(nodeKey.ID())
|
||||
valPubKey = ReadOrCreatePrivValidator(config.PrivValidatorFile())
|
||||
return
|
||||
}
|
||||
|
||||
func initWithConfig(cdc *codec.Codec, config *cfg.Config, initCfg initConfig) (
|
||||
appMessage json.RawMessage, err error) {
|
||||
genFile := config.GenesisFile()
|
||||
if !initCfg.Overwrite && common.FileExists(genFile) {
|
||||
err = fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||
return
|
||||
}
|
||||
|
||||
// process genesis transactions, else create default genesis.json
|
||||
var appGenTxs []auth.StdTx
|
||||
var persistentPeers string
|
||||
var genTxs []json.RawMessage
|
||||
var appState json.RawMessage
|
||||
var jsonRawTx json.RawMessage
|
||||
chainID := initCfg.ChainID
|
||||
|
||||
if initCfg.WithTxs {
|
||||
_, appGenTxs, persistentPeers, err = app.CollectStdTxs(config.Moniker, initCfg.GenTxsDir, cdc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs = make([]json.RawMessage, len(appGenTxs))
|
||||
config.P2P.PersistentPeers = persistentPeers
|
||||
for i, stdTx := range appGenTxs {
|
||||
jsonRawTx, err = cdc.MarshalJSON(stdTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs[i] = jsonRawTx
|
||||
}
|
||||
} else {
|
||||
var ip, keyPass, secret string
|
||||
var addr sdk.AccAddress
|
||||
var signedTx auth.StdTx
|
||||
|
||||
if initCfg.Name == "" {
|
||||
err = errors.New("must specify validator's moniker (--name)")
|
||||
return
|
||||
}
|
||||
|
||||
config.Moniker = initCfg.Name
|
||||
ip, err = server.ExternalIP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
memo := fmt.Sprintf("%s@%s:26656", initCfg.NodeID, ip)
|
||||
buf := client.BufferStdin()
|
||||
prompt := fmt.Sprintf("Password for account %q (default: %q):", initCfg.Name, app.DefaultKeyPass)
|
||||
keyPass, err = client.GetPassword(prompt, buf)
|
||||
if err != nil && keyPass != "" {
|
||||
// An error was returned that either failed to read the password from
|
||||
// STDIN or the given password is not empty but failed to meet minimum
|
||||
// length requirements.
|
||||
return
|
||||
}
|
||||
if keyPass == "" {
|
||||
keyPass = app.DefaultKeyPass
|
||||
}
|
||||
|
||||
addr, secret, err = server.GenerateSaveCoinKey(initCfg.ClientHome, initCfg.Name, keyPass, initCfg.OverwriteKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appMessage, err = json.Marshal(map[string]string{"secret": secret})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr),
|
||||
initCfg.ValPubKey,
|
||||
sdk.NewInt64Coin("steak", 100),
|
||||
stake.NewDescription(config.Moniker, "", "", ""),
|
||||
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
)
|
||||
txBldr := authtx.NewTxBuilderFromCLI().WithCodec(cdc).WithMemo(memo).WithChainID(chainID)
|
||||
signedTx, err = txBldr.SignStdTx(
|
||||
initCfg.Name, keyPass, auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo), false,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
jsonRawTx, err = cdc.MarshalJSON(signedTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs = []json.RawMessage{jsonRawTx}
|
||||
}
|
||||
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
appState, err = app.GaiaAppGenStateJSON(cdc, genTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = WriteGenesisFile(genFile, chainID, nil, appState)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// WriteGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
// nolint: unparam
|
||||
func WriteGenesisFile(genesisFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage) error {
|
||||
genDoc := types.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
AppState: appState,
|
||||
}
|
||||
|
||||
if err := genDoc.ValidateAndComplete(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return genDoc.SaveAs(genesisFile)
|
||||
}
|
||||
|
||||
// read of create the private key file for this config
|
||||
func ReadOrCreatePrivValidator(privValFile string) crypto.PubKey {
|
||||
// private validator
|
||||
var privValidator *privval.FilePV
|
||||
if common.FileExists(privValFile) {
|
||||
privValidator = privval.LoadFilePV(privValFile)
|
||||
} else {
|
||||
privValidator = privval.GenFilePV(privValFile)
|
||||
privValidator.Save()
|
||||
}
|
||||
return privValidator.GetPubKey()
|
||||
}
|
||||
|
|
|
@ -42,7 +42,6 @@ func setupClientHome(t *testing.T) func() {
|
|||
clientDir, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||
require.Nil(t, err)
|
||||
viper.Set(flagClientHome, clientDir)
|
||||
viper.Set(flagOverwriteKey, true)
|
||||
return func() {
|
||||
if err := os.RemoveAll(clientDir); err != nil {
|
||||
// TODO: Handle with #870
|
||||
|
|
|
@ -3,6 +3,10 @@ package init
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
@ -10,9 +14,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -20,22 +21,25 @@ import (
|
|||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
)
|
||||
|
||||
var (
|
||||
nodeDirPrefix = "node-dir-prefix"
|
||||
nValidators = "v"
|
||||
outputDir = "output-dir"
|
||||
nodeDaemonHome = "node-daemon-home"
|
||||
nodeCliHome = "node-cli-home"
|
||||
|
||||
startingIPAddress = "starting-ip-address"
|
||||
flagNodeDirPrefix = "node-dir-prefix"
|
||||
flagNumValidators = "v"
|
||||
flagOutputDir = "output-dir"
|
||||
flagNodeDaemonHome = "node-daemon-home"
|
||||
flagNodeCliHome = "node-cli-home"
|
||||
flagStartingIPAddress = "starting-ip-address"
|
||||
)
|
||||
|
||||
const nodeDirPerm = 0755
|
||||
|
||||
// get cmd to initialize all files for tendermint testnet and application
|
||||
func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec,
|
||||
appInit server.AppInit) *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "testnet",
|
||||
Short: "Initialize files for a Gaiad testnet",
|
||||
|
@ -45,48 +49,59 @@ necessary files (private validator, genesis, config, etc.).
|
|||
Note, strict routability for addresses is turned off in the config file.
|
||||
|
||||
Example:
|
||||
|
||||
gaiad testnet --v 4 --o ./output --starting-ip-address 192.168.10.2
|
||||
gaiad testnet --v 4 --output-dir ./output --starting-ip-address 192.168.10.2
|
||||
`,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
return testnetWithConfig(config, cdc, appInit)
|
||||
return initTestnet(config, cdc)
|
||||
},
|
||||
}
|
||||
cmd.Flags().Int(nValidators, 4,
|
||||
"Number of validators to initialize the testnet with")
|
||||
cmd.Flags().StringP(outputDir, "o", "./mytestnet",
|
||||
"Directory to store initialization data for the testnet")
|
||||
cmd.Flags().String(nodeDirPrefix, "node",
|
||||
"Prefix the directory name for each node with (node results in node0, node1, ...)")
|
||||
cmd.Flags().String(nodeDaemonHome, "gaiad",
|
||||
"Home directory of the node's daemon configuration")
|
||||
cmd.Flags().String(nodeCliHome, "gaiacli",
|
||||
"Home directory of the node's cli configuration")
|
||||
|
||||
cmd.Flags().String(startingIPAddress, "192.168.0.1",
|
||||
cmd.Flags().Int(flagNumValidators, 4,
|
||||
"Number of validators to initialize the testnet with",
|
||||
)
|
||||
cmd.Flags().StringP(flagOutputDir, "o", "./mytestnet",
|
||||
"Directory to store initialization data for the testnet",
|
||||
)
|
||||
cmd.Flags().String(flagNodeDirPrefix, "node",
|
||||
"Prefix the directory name for each node with (node results in node0, node1, ...)",
|
||||
)
|
||||
cmd.Flags().String(flagNodeDaemonHome, "gaiad",
|
||||
"Home directory of the node's daemon configuration",
|
||||
)
|
||||
cmd.Flags().String(flagNodeCliHome, "gaiacli",
|
||||
"Home directory of the node's cli configuration",
|
||||
)
|
||||
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1",
|
||||
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppInit) error {
|
||||
outDir := viper.GetString(outputDir)
|
||||
numValidators := viper.GetInt(nValidators)
|
||||
func initTestnet(config *cfg.Config, cdc *codec.Codec) error {
|
||||
outDir := viper.GetString(flagOutputDir)
|
||||
numValidators := viper.GetInt(flagNumValidators)
|
||||
|
||||
// Generate genesis.json and config.toml
|
||||
chainID := "chain-" + cmn.RandStr(6)
|
||||
|
||||
monikers := make([]string, numValidators)
|
||||
nodeIDs := make([]string, numValidators)
|
||||
valPubKeys := make([]crypto.PubKey, numValidators)
|
||||
|
||||
// Generate private key, node ID, initial transaction
|
||||
var (
|
||||
accs []app.GenesisAccount
|
||||
genFiles []string
|
||||
)
|
||||
|
||||
// generate private keys, node IDs, and initial transactions
|
||||
for i := 0; i < numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
|
||||
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
|
||||
nodeCliHomeName := viper.GetString(nodeCliHome)
|
||||
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(flagNodeDirPrefix), i)
|
||||
nodeDaemonHomeName := viper.GetString(flagNodeDaemonHome)
|
||||
nodeCliHomeName := viper.GetString(flagNodeCliHome)
|
||||
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
|
||||
clientDir := filepath.Join(outDir, nodeDirName, nodeCliHomeName)
|
||||
gentxsDir := filepath.Join(outDir, "gentxs")
|
||||
|
||||
config.SetRoot(nodeDir)
|
||||
|
||||
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm)
|
||||
|
@ -103,20 +118,27 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
|
||||
monikers = append(monikers, nodeDirName)
|
||||
config.Moniker = nodeDirName
|
||||
ip, err := getIP(i)
|
||||
|
||||
ip, err := getIP(i, viper.GetString(flagStartingIPAddress))
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
|
||||
nodeIDs[i], valPubKeys[i], err = InitializeNodeValidatorFiles(config)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
|
||||
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
|
||||
genFiles = append(genFiles, config.GenesisFile())
|
||||
|
||||
buf := client.BufferStdin()
|
||||
prompt := fmt.Sprintf("Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass)
|
||||
prompt := fmt.Sprintf(
|
||||
"Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass,
|
||||
)
|
||||
|
||||
keyPass, err := client.GetPassword(prompt, buf)
|
||||
if err != nil && keyPass != "" {
|
||||
// An error was returned that either failed to read the password from
|
||||
|
@ -124,6 +146,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
// length requirements.
|
||||
return err
|
||||
}
|
||||
|
||||
if keyPass == "" {
|
||||
keyPass = app.DefaultKeyPass
|
||||
}
|
||||
|
@ -133,17 +156,28 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
|
||||
info := map[string]string{"secret": secret}
|
||||
|
||||
cliPrint, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Save private key seed words
|
||||
|
||||
// save private key seed words
|
||||
err = writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, cliPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accs = append(accs, app.GenesisAccount{
|
||||
Address: addr,
|
||||
Coins: sdk.Coins{
|
||||
sdk.NewInt64Coin(fmt.Sprintf("%sToken", nodeDirName), 1000),
|
||||
sdk.NewInt64Coin("steak", 150),
|
||||
},
|
||||
})
|
||||
|
||||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr),
|
||||
valPubKeys[i],
|
||||
|
@ -153,6 +187,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
)
|
||||
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo)
|
||||
txBldr := authtx.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo)
|
||||
|
||||
signedTx, err := txBldr.SignStdTx(nodeDirName, app.DefaultKeyPass, tx, false)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
|
@ -165,7 +200,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
return err
|
||||
}
|
||||
|
||||
// Gather gentxs folder
|
||||
// gather gentxs folder
|
||||
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
|
@ -173,64 +208,140 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
}
|
||||
}
|
||||
|
||||
if err := initGenFiles(cdc, chainID, accs, genFiles, numValidators); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := collectGenFiles(
|
||||
cdc, config, chainID, monikers, nodeIDs, valPubKeys, numValidators,
|
||||
outDir, viper.GetString(flagNodeDirPrefix), viper.GetString(flagNodeDaemonHome),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully initialized %d node directories\n", numValidators)
|
||||
return nil
|
||||
}
|
||||
|
||||
func initGenFiles(
|
||||
cdc *codec.Codec, chainID string, accs []app.GenesisAccount,
|
||||
genFiles []string, numValidators int,
|
||||
) error {
|
||||
|
||||
appGenState := app.NewDefaultGenesisState()
|
||||
appGenState.Accounts = accs
|
||||
|
||||
appGenStateJSON, err := codec.MarshalJSONIndent(cdc, appGenState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genDoc := types.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
AppState: appGenStateJSON,
|
||||
Validators: nil,
|
||||
}
|
||||
|
||||
// generate empty genesis files for each validator and save
|
||||
for i := 0; i < numValidators; i++ {
|
||||
|
||||
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
|
||||
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
|
||||
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
|
||||
gentxsDir := filepath.Join(outDir, "gentxs")
|
||||
moniker := monikers[i]
|
||||
config.Moniker = nodeDirName
|
||||
config.SetRoot(nodeDir)
|
||||
|
||||
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
|
||||
// Run `init` and generate genesis.json and config.toml
|
||||
initCfg := initConfig{
|
||||
ChainID: chainID,
|
||||
GenTxsDir: gentxsDir,
|
||||
Name: moniker,
|
||||
WithTxs: true,
|
||||
Overwrite: true,
|
||||
OverwriteKey: false,
|
||||
NodeID: nodeID,
|
||||
ValPubKey: valPubKey,
|
||||
}
|
||||
if _, err := initWithConfig(cdc, config, initCfg); err != nil {
|
||||
if err := genDoc.SaveAs(genFiles[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully initialized %v node directories\n", viper.GetInt(nValidators))
|
||||
return nil
|
||||
}
|
||||
|
||||
func getIP(i int) (ip string, err error) {
|
||||
ip = viper.GetString(startingIPAddress)
|
||||
if len(ip) == 0 {
|
||||
func collectGenFiles(
|
||||
cdc *codec.Codec, config *cfg.Config, chainID string,
|
||||
monikers, nodeIDs []string, valPubKeys []crypto.PubKey,
|
||||
numValidators int, outDir, nodeDirPrefix, nodeDaemonHomeName string,
|
||||
) error {
|
||||
|
||||
var appState json.RawMessage
|
||||
genTime := tmtime.Now()
|
||||
|
||||
for i := 0; i < numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
|
||||
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
|
||||
gentxsDir := filepath.Join(outDir, "gentxs")
|
||||
moniker := monikers[i]
|
||||
config.Moniker = nodeDirName
|
||||
|
||||
config.SetRoot(nodeDir)
|
||||
|
||||
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
|
||||
initCfg := initConfig{
|
||||
ChainID: chainID,
|
||||
GenTxsDir: gentxsDir,
|
||||
Name: moniker,
|
||||
NodeID: nodeID,
|
||||
ValPubKey: valPubKey,
|
||||
}
|
||||
|
||||
genDoc, err := loadGenesisDoc(cdc, config.GenesisFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeAppState, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if appState == nil {
|
||||
// set the canonical application state (they should not differ)
|
||||
appState = nodeAppState
|
||||
}
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
|
||||
// overwrite each validator's genesis file to have a canonical genesis time
|
||||
err = ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getIP(i int, startingIPAddr string) (string, error) {
|
||||
var (
|
||||
ip string
|
||||
err error
|
||||
)
|
||||
|
||||
if len(startingIPAddr) == 0 {
|
||||
ip, err = server.ExternalIP()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
ip, err = calculateIP(ip, i)
|
||||
ip, err = calculateIP(startingIPAddr, i)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func writeFile(name string, dir string, contents []byte) error {
|
||||
writePath := filepath.Join(dir)
|
||||
file := filepath.Join(writePath, name)
|
||||
|
||||
err := cmn.EnsureDir(writePath, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cmn.WriteFile(file, contents, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -243,5 +354,6 @@ func calculateIP(ip string, i int) (string, error) {
|
|||
for j := 0; j < i; j++ {
|
||||
ipv4[3]++
|
||||
}
|
||||
|
||||
return ipv4.String(), nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// ExportGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
func ExportGenesisFile(
|
||||
genFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage,
|
||||
) error {
|
||||
|
||||
genDoc := types.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
AppState: appState,
|
||||
}
|
||||
|
||||
if err := genDoc.ValidateAndComplete(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return genDoc.SaveAs(genFile)
|
||||
}
|
||||
|
||||
// ExportGenesisFileWithTime creates and writes the genesis configuration to disk.
|
||||
// An error is returned if building or writing the configuration to file fails.
|
||||
func ExportGenesisFileWithTime(
|
||||
genFile, chainID string, validators []types.GenesisValidator,
|
||||
appState json.RawMessage, genTime time.Time,
|
||||
) error {
|
||||
|
||||
genDoc := types.GenesisDoc{
|
||||
GenesisTime: genTime,
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
AppState: appState,
|
||||
}
|
||||
|
||||
if err := genDoc.ValidateAndComplete(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return genDoc.SaveAs(genFile)
|
||||
}
|
||||
|
||||
// read of create the private key file for this config
|
||||
func ReadOrCreatePrivValidator(privValFile string) crypto.PubKey {
|
||||
var privValidator *privval.FilePV
|
||||
|
||||
if common.FileExists(privValFile) {
|
||||
privValidator = privval.LoadFilePV(privValFile)
|
||||
} else {
|
||||
privValidator = privval.GenFilePV(privValFile)
|
||||
privValidator.Save()
|
||||
}
|
||||
|
||||
return privValidator.GetPubKey()
|
||||
}
|
||||
|
||||
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
|
||||
func InitializeNodeValidatorFiles(
|
||||
config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error,
|
||||
) {
|
||||
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return nodeID, valPubKey, err
|
||||
}
|
||||
|
||||
nodeID = string(nodeKey.ID())
|
||||
valPubKey = ReadOrCreatePrivValidator(config.PrivValidatorFile())
|
||||
|
||||
return nodeID, valPubKey, nil
|
||||
}
|
||||
|
||||
func loadGenesisDoc(cdc *amino.Codec, genFile string) (genDoc types.GenesisDoc, err error) {
|
||||
genContents, err := ioutil.ReadFile(genFile)
|
||||
if err != nil {
|
||||
return genDoc, err
|
||||
}
|
||||
|
||||
if err := cdc.UnmarshalJSON(genContents, &genDoc); err != nil {
|
||||
return genDoc, err
|
||||
}
|
||||
|
||||
return genDoc, err
|
||||
}
|
||||
|
||||
func initializeEmptyGenesis(
|
||||
cdc *codec.Codec, genFile, chainID string, overwrite bool,
|
||||
) (appState json.RawMessage, err error) {
|
||||
|
||||
if !overwrite && common.FileExists(genFile) {
|
||||
return nil, fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||
}
|
||||
|
||||
return codec.MarshalJSONIndent(cdc, app.NewDefaultGenesisState())
|
||||
}
|
|
@ -273,7 +273,7 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig []byte, pub t
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cdc.MustUnmarshalBinary([]byte(signed), sig)
|
||||
cdc.MustUnmarshalBinaryLengthPrefixed([]byte(signed), sig)
|
||||
return sig, linfo.GetPubKey(), nil
|
||||
}
|
||||
sig, err = priv.Sign(msg)
|
||||
|
|
|
@ -182,11 +182,11 @@ func (i offlineInfo) GetAddress() types.AccAddress {
|
|||
|
||||
// encoding info
|
||||
func writeInfo(i Info) []byte {
|
||||
return cdc.MustMarshalBinary(i)
|
||||
return cdc.MustMarshalBinaryLengthPrefixed(i)
|
||||
}
|
||||
|
||||
// decoding info
|
||||
func readInfo(bz []byte) (info Info, err error) {
|
||||
err = cdc.UnmarshalBinary(bz, &info)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(bz, &info)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -72,8 +72,8 @@ module.exports = {
|
|||
title: "Light Client",
|
||||
collapsable: false,
|
||||
children: [
|
||||
"/light/",
|
||||
"/light/getting_started"
|
||||
"/lite/",
|
||||
"/lite/getting_started"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
- Tags [#1780](https://github.com/cosmos/cosmos-sdk/issues/1780)
|
||||
# Lower priority
|
||||
|
||||
- Create some diagrams (see `docs/resources/diagrams/todo.md`)
|
||||
|
||||
## Governance v2
|
||||
|
||||
- Circuit breaker - https://github.com/cosmos/cosmos-sdk/issues/926
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
module.exports = {
|
||||
title: "Cosmos Network",
|
||||
description: "Documentation for the Cosmos Network.",
|
||||
dest: "./dist/docs",
|
||||
base: "/docs/",
|
||||
markdown: {
|
||||
lineNumbers: true
|
||||
},
|
||||
themeConfig: {
|
||||
lastUpdated: "Last Updated",
|
||||
nav: [{ text: "Back to Cosmos", link: "https://cosmos.network" }],
|
||||
sidebar: [
|
||||
{
|
||||
title: "Introduction",
|
||||
collapsable: false,
|
||||
children: [
|
||||
"/introduction/cosmos-hub",
|
||||
"/introduction/tendermint",
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Getting Started",
|
||||
collapsable: false,
|
||||
children: [
|
||||
"/getting-started/voyager",
|
||||
"/getting-started/installation",
|
||||
"/getting-started/full-node",
|
||||
"/getting-started/create-testnet"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Cosmos SDK",
|
||||
collapsable: false,
|
||||
children: [
|
||||
["/sdk/overview", "Overview"],
|
||||
["/sdk/core/intro", "Core"],
|
||||
"/sdk/core/app1",
|
||||
"/sdk/core/app2",
|
||||
"/sdk/core/app3",
|
||||
"/sdk/core/app4",
|
||||
"/sdk/core/app5",
|
||||
// "/sdk/modules",
|
||||
"/sdk/clients"
|
||||
]
|
||||
},
|
||||
// {
|
||||
// title: "Specifications",
|
||||
// collapsable: false,
|
||||
// children: [
|
||||
// ["/specs/overview", "Overview"],
|
||||
// "/specs/governance",
|
||||
// "/specs/ibc",
|
||||
// "/specs/staking",
|
||||
// "/specs/icts",
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
title: "Lotion JS",
|
||||
collapsable: false,
|
||||
children: [["/lotion/overview", "Overview"], "/lotion/building-an-app"]
|
||||
},
|
||||
{
|
||||
title: "Validators",
|
||||
collapsable: false,
|
||||
children: [
|
||||
["/validators/overview", "Overview"],
|
||||
["/validators/security", "Security"],
|
||||
["/validators/validator-setup", "Validator Setup"],
|
||||
"/validators/validator-faq"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Resources",
|
||||
collapsable: false,
|
||||
children: [
|
||||
// ["/resources/faq" "General"],
|
||||
"/resources/delegator-faq",
|
||||
["/resources/whitepaper", "Whitepaper - English"],
|
||||
["/resources/whitepaper-ko", "Whitepaper - 한국어"],
|
||||
["/resources/whitepaper-zh-CN", "Whitepaper - 中文"],
|
||||
["/resources/whitepaper-pt", "Whitepaper - Português"]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
The following diagrams should be created to aid in comprehension of the SDK:
|
||||
- Genesis circuit
|
||||
- App structure (aka use of baseapp in something like gaia)
|
||||
- Simulation framework
|
||||
- Slashing Mechanism
|
||||
- Staking Mechanism
|
||||
- Staking/Slashing Mechanism specific to use of hooks
|
||||
- Governance Mechanism
|
||||
- Distribution Mechanism
|
||||
- Inflation Mechanism (easier)
|
||||
- IBC Mechanism
|
||||
|
||||
These diagrams should reference specific structs/interfaces from the codebase,
|
||||
logic flow and interconnectivity with other mechanisms etc. It's recommended that
|
||||
https://www.draw.io/ be used, hence the raw diagram xml can be saved directly to
|
||||
the Cosmos-SDK repo and adapted with the codebase.
|
||||
|
|
@ -181,6 +181,12 @@ gaiacli tx sign \
|
|||
unsignedSendTx.json > signedSendTx.json
|
||||
```
|
||||
|
||||
You can validate the transaction's signagures by typing the following:
|
||||
|
||||
```bash
|
||||
gaiacli tx sign --validate-signatures signedSendTx.json
|
||||
```
|
||||
|
||||
You can broadcast the signed transaction to a node by providing the JSON file to the following command:
|
||||
|
||||
```
|
||||
|
@ -285,7 +291,13 @@ Or if you want to check all your current unbonding-delegations with disctinct va
|
|||
gaiacli query unbonding-delegations <account_cosmos>
|
||||
```
|
||||
|
||||
You can also get previous unbonding-delegation(s) status by adding the `--height` flag.
|
||||
Additionally, as you can get all the unbonding-delegations from a particular validator:
|
||||
|
||||
```bash
|
||||
gaiacli query unbonding-delegations-from <account_cosmosval>
|
||||
```
|
||||
|
||||
To get previous unbonding-delegation(s) status on past blocks, try adding the `--height` flag.
|
||||
|
||||
#### Redelegate Tokens
|
||||
|
||||
|
@ -321,7 +333,13 @@ Or if you want to check all your current unbonding-delegations with disctinct va
|
|||
gaiacli query redelegations <account_cosmos>
|
||||
```
|
||||
|
||||
You can also get previous redelegation(s) status by adding the `--height` flag.
|
||||
Additionally, as you can get all the outgoing redelegations from a particular validator:
|
||||
|
||||
```bash
|
||||
gaiacli query redelegations-from <account_cosmosval>
|
||||
```
|
||||
|
||||
To get previous redelegation(s) status on past blocks, try adding the `--height` flag.
|
||||
|
||||
### Governance
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ func (tx app2Tx) GetMsgs() []sdk.Msg {
|
|||
func tx2Decoder(cdc *codec.Codec) sdk.TxDecoder {
|
||||
return func(txBytes []byte) (sdk.Tx, sdk.Error) {
|
||||
var tx app2Tx
|
||||
err := cdc.UnmarshalBinary(txBytes, &tx)
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrTxDecode(err.Error())
|
||||
}
|
||||
|
|
|
@ -201,7 +201,7 @@ func (tx app2Tx) GetSignature() []byte {
|
|||
func tx2Decoder(cdc *codec.Codec) sdk.TxDecoder {
|
||||
return func(txBytes []byte) (sdk.Tx, sdk.Error) {
|
||||
var tx app2Tx
|
||||
err := cdc.UnmarshalBinary(txBytes, &tx)
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrTxDecode(err.Error())
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func TestEncoding(t *testing.T) {
|
|||
cdc := NewCodec()
|
||||
testTxDecoder := tx2Decoder(cdc)
|
||||
|
||||
encodedSendTx, err := cdc.MarshalBinary(sendTxBefore)
|
||||
encodedSendTx, err := cdc.MarshalBinaryLengthPrefixed(sendTxBefore)
|
||||
|
||||
require.Nil(t, err, "Error encoding sendTx")
|
||||
|
||||
|
@ -69,7 +69,7 @@ func TestEncoding(t *testing.T) {
|
|||
Signature: sig,
|
||||
}
|
||||
|
||||
encodedIssueTx, err2 := cdc.MarshalBinary(issueTxBefore)
|
||||
encodedIssueTx, err2 := cdc.MarshalBinaryLengthPrefixed(issueTxBefore)
|
||||
|
||||
require.Nil(t, err2, "Error encoding issueTx")
|
||||
|
||||
|
|
|
@ -1,159 +1,469 @@
|
|||
## Vesting
|
||||
# Vesting
|
||||
|
||||
### Intro and Requirements
|
||||
<!-- TOC -->
|
||||
|
||||
This paper specifies vesting account implementation for the Cosmos Hub.
|
||||
The requirements for this vesting account is that it should be initialized during genesis with
|
||||
a starting balance X coins and a vesting endtime T. The owner of this account should be able to delegate to validators
|
||||
and vote with locked coins, however they cannot send locked coins to other accounts until those coins have been unlocked.
|
||||
The vesting account should also be able to spend any coins it receives from other users.
|
||||
Thus, the bank module's `MsgSend` handler should error if a vesting account is trying to send an amount that exceeds their
|
||||
unlocked coin amount.
|
||||
- [Vesting](#vesting)
|
||||
- [Intro and Requirements](#intro-and-requirements)
|
||||
- [Vesting Account Types](#vesting-account-types)
|
||||
- [Vesting Account Specification](#vesting-account-specification)
|
||||
- [Determining Vesting & Vested Amounts](#determining-vesting--vested-amounts)
|
||||
- [Continuously Vesting Accounts](#continuously-vesting-accounts)
|
||||
- [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts)
|
||||
- [Transferring/Sending](#transferringsending)
|
||||
- [Continuously Vesting Accounts](#continuously-vesting-accounts-1)
|
||||
- [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts-1)
|
||||
- [Keepers/Handlers](#keepershandlers)
|
||||
- [Delegating](#delegating)
|
||||
- [Continuously Vesting Accounts](#continuously-vesting-accounts-2)
|
||||
- [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts-2)
|
||||
- [Keepers/Handlers](#keepershandlers-1)
|
||||
- [Undelegating](#undelegating)
|
||||
- [Continuously Vesting Accounts](#continuously-vesting-accounts-3)
|
||||
- [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts-3)
|
||||
- [Keepers/Handlers](#keepershandlers-2)
|
||||
- [Keepers & Handlers](#keepers--handlers)
|
||||
- [Initializing at Genesis](#initializing-at-genesis)
|
||||
- [Examples](#examples)
|
||||
- [Simple](#simple)
|
||||
- [Slashing](#slashing)
|
||||
- [Glossary](#glossary)
|
||||
|
||||
### Implementation
|
||||
<!-- /TOC -->
|
||||
|
||||
##### Vesting Account implementation
|
||||
## Intro and Requirements
|
||||
|
||||
NOTE: `Now = ctx.BlockHeader().Time`
|
||||
This paper specifies vesting account implementation for the Cosmos Hub.
|
||||
The requirements for this vesting account is that it should be initialized
|
||||
during genesis with a starting balance `X` coins and a vesting end time `T`.
|
||||
|
||||
The owner of this account should be able to delegate to validators
|
||||
and vote with locked coins, however they cannot send locked coins to other
|
||||
accounts until those coins have been unlocked. When it comes to governance, it
|
||||
is yet undefined if we want to allow a vesting account to be able to deposit
|
||||
vesting coins into proposals.
|
||||
|
||||
In addition, a vesting account vests all of its coin denominations at the same
|
||||
rate. This may be subject to change.
|
||||
|
||||
**Note**: A vesting account could have some vesting and non-vesting coins. To
|
||||
support such a feature, the `GenesisAccount` type will need to be updated in
|
||||
order to make such a distinction.
|
||||
|
||||
## Vesting Account Types
|
||||
|
||||
```go
|
||||
// VestingAccount defines an interface that any vesting account type must
|
||||
// implement.
|
||||
type VestingAccount interface {
|
||||
Account
|
||||
AssertIsVestingAccount() // existence implies that account is vesting.
|
||||
AssertIsVestingAccount() // existence implies that account is vesting
|
||||
|
||||
// Calculates amount of coins that can be sent to other accounts given the current time
|
||||
SendableCoins(sdk.Context) sdk.Coins
|
||||
// Calculates the amount of coins that can be sent to other accounts given
|
||||
// the current time.
|
||||
SpendableCoins(Context) Coins
|
||||
// Performs delegation accounting.
|
||||
TrackDelegation(amount)
|
||||
// Performs undelegation accounting.
|
||||
TrackUndelegation(amount)
|
||||
}
|
||||
|
||||
// Implements Vesting Account
|
||||
// Continuously vests by unlocking coins linearly with respect to time
|
||||
// BaseVestingAccount implements the VestingAccount interface. It contains all
|
||||
// the necessary fields needed for any vesting account implementation.
|
||||
type BaseVestingAccount struct {
|
||||
BaseAccount
|
||||
|
||||
OriginalVesting Coins // coins in account upon initialization
|
||||
DelegatedFree Coins // coins that are vested and delegated
|
||||
EndTime Time // when the coins become unlocked
|
||||
}
|
||||
|
||||
// ContinuousVestingAccount implements the VestingAccount interface. It
|
||||
// continuously vests by unlocking coins linearly with respect to time.
|
||||
type ContinuousVestingAccount struct {
|
||||
BaseAccount
|
||||
OriginalVestingCoins sdk.Coins // Coins in account on Initialization
|
||||
ReceivedCoins sdk.Coins // Coins received from other accounts
|
||||
SentCoins sdk.Coins // Coins sent to other accounts
|
||||
BaseVestingAccount
|
||||
|
||||
// StartTime and EndTime used to calculate how much of OriginalCoins is unlocked at any given point
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
DelegatedVesting Coins // coins that vesting and delegated
|
||||
StartTime Time // when the coins start to vest
|
||||
}
|
||||
|
||||
// Uses time in context to calculate total unlocked coins
|
||||
SendableCoins(vacc ContinuousVestingAccount, ctx sdk.Context) sdk.Coins:
|
||||
|
||||
// Coins unlocked by vesting schedule
|
||||
unlockedCoins := ReceivedCoins - SentCoins + OriginalVestingCoins * (Now - StartTime) / (EndTime - StartTime)
|
||||
|
||||
// Must still check for currentCoins constraint since some unlocked coins may have been delegated.
|
||||
currentCoins := vacc.BaseAccount.GetCoins()
|
||||
|
||||
// min will return sdk.Coins with each denom having the minimum amount from unlockedCoins and currentCoins
|
||||
return min(unlockedCoins, currentCoins)
|
||||
|
||||
// DelayedVestingAccount implements the VestingAccount interface. It vests all
|
||||
// coins after a specific time, but non prior. In other words, it keeps them
|
||||
// locked until a specified time.
|
||||
type DelayedVestingAccount struct {
|
||||
BaseAccount
|
||||
BaseVestingAccount
|
||||
}
|
||||
```
|
||||
|
||||
The `VestingAccount` interface is used to assert that an account is a vesting account like so:
|
||||
## Vesting Account Specification
|
||||
|
||||
Given a vesting account, we define the following in the proceeding operations:
|
||||
|
||||
- `OV`: The original vesting coin amount. It is a constant value.
|
||||
- `V`: The number of `OV` coins that are still _vesting_. It is derived by `OV`, `StartTime` and `EndTime`. This value is computed on demand and not on a per-block basis.
|
||||
- `V'`: The number of `OV` coins that are _vested_ (unlocked). This value is computed on demand and not a per-block basis.
|
||||
- `DV`: The number of delegated _vesting_ coins. It is a variable value. It is stored and modified directly in the vesting account.
|
||||
- `DF`: The number of delegated _vested_ (unlocked) coins. It is a variable value. It is stored and modified directly in the vesting account.
|
||||
- `BC`: The number of `OV` coins less any coins that are transferred, which can be negative, or delegated (`DV + DF`). It is considered to be balance of the embedded base account. It is stored and modified directly in the vesting account.
|
||||
|
||||
### Determining Vesting & Vested Amounts
|
||||
|
||||
It is important to note that these values are computed on demand and not on a
|
||||
mandatory per-block basis.
|
||||
|
||||
#### Continuously Vesting Accounts
|
||||
|
||||
To determine the amount of coins that are vested for a given block `B`, the
|
||||
following is performed:
|
||||
|
||||
1. Compute `X := B.Time - StartTime`
|
||||
2. Compute `Y := EndTime - StartTime`
|
||||
3. Compute `V' := OV * (X / Y)`
|
||||
4. Compute `V := OV - V'`
|
||||
|
||||
Thus, the total amount of _vested_ coins is `V'` and the remaining amount, `V`,
|
||||
is _vesting_.
|
||||
|
||||
```go
|
||||
vacc, ok := acc.(VestingAccount); ok
|
||||
func (cva ContinuousVestingAccount) GetVestedCoins(b Block) Coins {
|
||||
// We must handle the case where the start time for a vesting account has
|
||||
// been set into the future or when the start of the chain is not exactly
|
||||
// known.
|
||||
if b.Time < va.StartTime {
|
||||
return ZeroCoins
|
||||
}
|
||||
|
||||
x := b.Time - cva.StartTime
|
||||
y := cva.EndTime - cva.StartTime
|
||||
|
||||
return cva.OriginalVesting * (x / y)
|
||||
}
|
||||
|
||||
func (cva ContinuousVestingAccount) GetVestingCoins(b Block) Coins {
|
||||
return cva.OriginalVesting - cva.GetVestedCoins(b)
|
||||
}
|
||||
```
|
||||
|
||||
as well as to calculate the SendableCoins at any given moment.
|
||||
#### Delayed/Discrete Vesting Accounts
|
||||
|
||||
The `ContinuousVestingAccount` struct implements the Vesting account interface. It uses `OriginalVestingCoins`, `ReceivedCoins`,
|
||||
`SentCoins`, `StartTime`, and `EndTime` to calculate how many coins are sendable at any given point.
|
||||
Since the vesting restrictions need to be implemented on a per-module basis, the `ContinuousVestingAccount` implements
|
||||
the `Account` interface exactly like `BaseAccount`. Thus, `ContinuousVestingAccount.GetCoins()` will return the total of
|
||||
both locked coins and unlocked coins currently in the account. Delegated coins are deducted from `Account.GetCoins()`, but do not count against unlocked coins because they are still at stake and will be reinstated (partially if slashed) after waiting the full unbonding period.
|
||||
|
||||
##### Changes to Keepers/Handler
|
||||
|
||||
Since a vesting account should be capable of doing everything but sending with its locked coins, the restriction should be
|
||||
handled at the `bank.Keeper` level. Specifically in methods that are explicitly used for sending like
|
||||
`sendCoins` and `inputOutputCoins`. These methods must check that an account is a vesting account using the check described above.
|
||||
Delayed vesting accounts are easier to reason about as they only have the full
|
||||
amount vesting up until a certain time, then they all become vested (unlocked).
|
||||
|
||||
```go
|
||||
if acc is VestingAccount and Now < vestingAccount.EndTime:
|
||||
// Check if amount is less than currently allowed sendable coins
|
||||
if msg.Amount > vestingAccount.SendableCoins(ctx) then fail
|
||||
else:
|
||||
vestingAccount.SentCoins += msg.Amount
|
||||
func (dva DelayedVestingAccount) GetVestedCoins(b Block) Coins {
|
||||
if b.Time >= dva.EndTime {
|
||||
return dva.OriginalVesting
|
||||
}
|
||||
|
||||
else:
|
||||
// Account has fully vested, treat like regular account
|
||||
if msg.Amount > account.GetCoins() then fail
|
||||
|
||||
// All checks passed, send the coins
|
||||
SendCoins(inputs, outputs)
|
||||
return ZeroCoins
|
||||
}
|
||||
|
||||
func (dva DelayedVestingAccount) GetVestingCoins(b Block) Coins {
|
||||
return cva.OriginalVesting - cva.GetVestedCoins(b)
|
||||
}
|
||||
```
|
||||
|
||||
Coins that are sent to a vesting account after initialization by users sending them coins should be spendable
|
||||
immediately after receiving them. Thus, handlers (like staking or bank) that send coins that a vesting account did not
|
||||
originally own should increment `ReceivedCoins` by the amount sent.
|
||||
Unlocked coins that are sent to other accounts will increment the vesting account's `SentCoins` attribute.
|
||||
### Transferring/Sending
|
||||
|
||||
CONTRACT: Handlers SHOULD NOT update `ReceivedCoins` if they were originally sent from the vesting account. For example, if a vesting account unbonds from a validator, their tokens should be added back to account but staking handlers SHOULD NOT update `ReceivedCoins`.
|
||||
However when a user sends coins to vesting account, then `ReceivedCoins` SHOULD be incremented.
|
||||
#### Continuously Vesting Accounts
|
||||
|
||||
### Initializing at Genesis
|
||||
At any given time, a continuous vesting account may transfer: `min((BC + DV) - V, BC)`.
|
||||
|
||||
To initialize both vesting accounts and base accounts, the `GenesisAccount` struct will include an EndTime. Accounts meant to be
|
||||
BaseAccounts will have `EndTime = 0`. The `initChainer` method will parse the GenesisAccount into BaseAccounts and VestingAccounts
|
||||
as appropriate.
|
||||
In other words, a vesting account may transfer the minimum of the base account
|
||||
balance and the base account balance plus the number of currently delegated
|
||||
vesting coins less the number of coins vested so far.
|
||||
|
||||
```go
|
||||
func (cva ContinuousVestingAccount) SpendableCoins() Coins {
|
||||
bc := cva.GetCoins()
|
||||
return min((bc + cva.DelegatedVesting) - cva.GetVestingCoins(), bc)
|
||||
}
|
||||
```
|
||||
|
||||
##### Delayed/Discrete Vesting Accounts
|
||||
|
||||
A delayed vesting account may send any coins it has received. In addition, if it
|
||||
has fully vested, it can send any of it's vested coins.
|
||||
|
||||
```go
|
||||
func (dva DelayedVestingAccount) SpendableCoins() Coins {
|
||||
bc := dva.GetCoins()
|
||||
return bc - dva.GetVestingCoins()
|
||||
}
|
||||
```
|
||||
|
||||
##### Keepers/Handlers
|
||||
|
||||
The corresponding `x/bank` keeper should appropriately handle sending coins
|
||||
based on if the account is a vesting account or not.
|
||||
|
||||
```go
|
||||
func SendCoins(from Account, to Account amount Coins) {
|
||||
if isVesting(from) {
|
||||
sc := from.SpendableCoins()
|
||||
} else {
|
||||
sc := from.GetCoins()
|
||||
}
|
||||
|
||||
if amount <= sc {
|
||||
from.SetCoins(sc - amount)
|
||||
to.SetCoins(amount)
|
||||
// save accounts...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Delegating
|
||||
|
||||
#### Continuously Vesting Accounts
|
||||
|
||||
For a continuous vesting account attempting to delegate `D` coins, the following
|
||||
is performed:
|
||||
|
||||
1. Verify `BC >= D > 0`
|
||||
2. Compute `X := min(max(V - DV, 0), D)` (portion of `D` that is vesting)
|
||||
3. Compute `Y := D - X` (portion of `D` that is free)
|
||||
4. Set `DV += X`
|
||||
5. Set `DF += Y`
|
||||
6. Set `BC -= D`
|
||||
|
||||
```go
|
||||
func (cva ContinuousVestingAccount) TrackDelegation(amount Coins) {
|
||||
x := min(max(cva.GetVestingCoins() - cva.DelegatedVesting, 0), amount)
|
||||
y := amount - x
|
||||
|
||||
cva.DelegatedVesting += x
|
||||
cva.DelegatedFree += y
|
||||
}
|
||||
```
|
||||
|
||||
##### Delayed/Discrete Vesting Accounts
|
||||
|
||||
For a delayed vesting account, it can only delegate with received coins and
|
||||
coins that are fully vested so we only need to update `DF`.
|
||||
|
||||
```go
|
||||
func (dva DelayedVestingAccount) TrackDelegation(amount Coins) {
|
||||
dva.DelegatedFree += amount
|
||||
}
|
||||
```
|
||||
|
||||
##### Keepers/Handlers
|
||||
|
||||
```go
|
||||
func DelegateCoins(from Account, amount Coins) {
|
||||
// canDelegate checks different semantics for continuous and delayed vesting
|
||||
// accounts
|
||||
if isVesting(from) && canDelegate(from) {
|
||||
sc := from.GetCoins()
|
||||
|
||||
if amount <= sc {
|
||||
from.TrackDelegation(amount)
|
||||
from.SetCoins(sc - amount)
|
||||
// save account...
|
||||
}
|
||||
} else {
|
||||
sc := from.GetCoins()
|
||||
|
||||
if amount <= sc {
|
||||
from.SetCoins(sc - amount)
|
||||
// save account...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Undelegating
|
||||
|
||||
#### Continuously Vesting Accounts
|
||||
|
||||
For a continuous vesting account attempting to undelegate `D` coins, the
|
||||
following is performed:
|
||||
|
||||
1. Verify `(DV + DF) >= D > 0` (this is simply a sanity check)
|
||||
2. Compute `Y := min(DF, D)` (portion of `D` that should become free, prioritizing free coins)
|
||||
3. Compute `X := D - Y` (portion of `D` that should remain vesting)
|
||||
4. Set `DV -= X`
|
||||
5. Set `DF -= Y`
|
||||
6. Set `BC += D`
|
||||
|
||||
```go
|
||||
func (cva ContinuousVestingAccount) TrackUndelegation(amount Coins) {
|
||||
y := min(cva.DelegatedFree, amount)
|
||||
x := amount - y
|
||||
|
||||
cva.DelegatedVesting -= x
|
||||
cva.DelegatedFree -= y
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: If a delegation is slashed, the continuous vesting account will end up
|
||||
with excess an `DV` amount, even after all its coins have vested. This is because
|
||||
undelegating free coins are prioritized.
|
||||
|
||||
##### Delayed/Discrete Vesting Accounts
|
||||
|
||||
For a delayed vesting account, it only needs to add back the `DF` amount since
|
||||
the account is fully vested.
|
||||
|
||||
```go
|
||||
func (dva DelayedVestingAccount) TrackUndelegation(amount Coins) {
|
||||
dva.DelegatedFree -= amount
|
||||
}
|
||||
```
|
||||
|
||||
##### Keepers/Handlers
|
||||
|
||||
```go
|
||||
func UndelegateCoins(to Account, amount Coins) {
|
||||
if isVesting(to) {
|
||||
if to.DelegatedFree + to.DelegatedVesting >= amount {
|
||||
to.TrackUndelegation(amount)
|
||||
AddCoins(to, amount)
|
||||
// save account ...
|
||||
}
|
||||
} else {
|
||||
AddCoins(to, amount)
|
||||
// save account...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Keepers & Handlers
|
||||
|
||||
The `VestingAccount` implementations reside in `x/auth`. However, any keeper in
|
||||
a module (e.g. staking in `x/stake`) wishing to potentially utilize any vesting
|
||||
coins, must call explicit methods on the `x/bank` keeper (e.g. `DelegateCoins`)
|
||||
opposed to `SendCoins` and `SubtractCoins`.
|
||||
|
||||
In addition, the vesting account should also be able to spend any coins it
|
||||
receives from other users. Thus, the bank module's `MsgSend` handler should
|
||||
error if a vesting account is trying to send an amount that exceeds their
|
||||
unlocked coin amount.
|
||||
|
||||
See the above specification for full implementation details.
|
||||
|
||||
## Initializing at Genesis
|
||||
|
||||
To initialize both vesting accounts and base accounts, the `GenesisAccount`
|
||||
struct will include an `EndTime`. Accounts meant to be of type `BaseAccount` will
|
||||
have `EndTime = 0`. The `initChainer` method will parse the GenesisAccount into
|
||||
BaseAccounts and VestingAccounts as appropriate.
|
||||
|
||||
```go
|
||||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
GenesisCoins sdk.Coins `json:"coins"`
|
||||
EndTime int64 `json:"lock"`
|
||||
Address sdk.AccAddress
|
||||
GenesisCoins sdk.Coins
|
||||
EndTime int64
|
||||
}
|
||||
|
||||
initChainer:
|
||||
for gacc in GenesisAccounts:
|
||||
func initChainer() {
|
||||
for genAcc in GenesisAccounts {
|
||||
baseAccount := BaseAccount{
|
||||
Address: gacc.Address,
|
||||
Coins: gacc.GenesisCoins,
|
||||
Address: genAcc.Address,
|
||||
Coins: genAcc.GenesisCoins,
|
||||
}
|
||||
if gacc.EndTime != 0:
|
||||
vestingAccount := ContinuouslyVestingAccount{
|
||||
BaseAccount: baseAccount,
|
||||
OriginalVestingCoins: gacc.GenesisCoins,
|
||||
StartTime: RequestInitChain.Time,
|
||||
EndTime: gacc.EndTime,
|
||||
}
|
||||
AddAccountToState(vestingAccount)
|
||||
else:
|
||||
AddAccountToState(baseAccount)
|
||||
|
||||
if genAcc.EndTime != 0 {
|
||||
vestingAccount := ContinuousVestingAccount{
|
||||
BaseAccount: baseAccount,
|
||||
OriginalVesting: genAcc.GenesisCoins,
|
||||
StartTime: RequestInitChain.Time,
|
||||
EndTime: genAcc.EndTime,
|
||||
}
|
||||
|
||||
AddAccountToState(vestingAccount)
|
||||
} else {
|
||||
AddAccountToState(baseAccount)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Formulas
|
||||
## Examples
|
||||
|
||||
`OriginalVestingCoins`: Amount of coins in account at Genesis
|
||||
### Simple
|
||||
|
||||
`CurrentCoins`: Coins currently in the baseaccount (both locked and unlocked: `vestingAccount.GetCoins`)
|
||||
Given a continuous vesting account with 10 vesting coins.
|
||||
|
||||
`ReceivedCoins`: Coins received from other accounts (always unlocked)
|
||||
```
|
||||
OV = 10
|
||||
DF = 0
|
||||
DV = 0
|
||||
BC = 10
|
||||
V = 10
|
||||
V' = 0
|
||||
```
|
||||
|
||||
`LockedCoins`: Coins that are currently locked
|
||||
1. Immediately receives 1 coin
|
||||
```
|
||||
BC = 11
|
||||
```
|
||||
2. Time passes, 2 coins vest
|
||||
```
|
||||
V = 8
|
||||
V' = 2
|
||||
```
|
||||
3. Delegates 4 coins to validator A
|
||||
```
|
||||
DV = 4
|
||||
BC = 7
|
||||
```
|
||||
4. Sends 3 coins
|
||||
```
|
||||
BC = 4
|
||||
```
|
||||
5. More time passes, 2 more coins vest
|
||||
```
|
||||
V = 6
|
||||
V' = 4
|
||||
```
|
||||
6. Sends 2 coins. At this point the account cannot send anymore until further coins vest or it receives additional coins. It can still however, delegate.
|
||||
```
|
||||
BC = 2
|
||||
```
|
||||
|
||||
`Delegated`: Coins that have been delegated (no longer in account; may be locked or unlocked)
|
||||
### Slashing
|
||||
|
||||
`Sent`: Coins sent to other accounts (MUST be unlocked)
|
||||
Same initial starting conditions as the simple example.
|
||||
|
||||
Maximum amount of coins vesting schedule allows to be sent:
|
||||
1. Time passes, 5 coins vest
|
||||
```
|
||||
V = 5
|
||||
V' = 5
|
||||
```
|
||||
2. Delegate 5 coins to validator A
|
||||
```
|
||||
DV = 5
|
||||
BC = 5
|
||||
```
|
||||
3. Delegate 5 coins to validator B
|
||||
```
|
||||
DF = 5
|
||||
BC = 0
|
||||
```
|
||||
4. Validator A gets slashed by 50%, making the delegation to A now worth 2.5 coins
|
||||
5. Undelegate from validator A (2.5 coins)
|
||||
```
|
||||
DF = 5 - 2.5 = 2.5
|
||||
BC = 0 + 2.5 = 2.5
|
||||
```
|
||||
6. Undelegate from validator B (5 coins). The account at this point can only send 2.5 coins unless it receives more coins or until more coins vest. It can still however, delegate.
|
||||
```
|
||||
DV = 5 - 2.5 = 2.5
|
||||
DF = 2.5 - 2.5 = 0
|
||||
BC = 2.5 + 5 = 7.5
|
||||
```
|
||||
|
||||
`ReceivedCoins - SentCoins + OriginalVestingCoins * (Now - StartTime) / (EndTime - StartTime)`
|
||||
Notice how we have an excess amount of `DV`.
|
||||
|
||||
`ReceivedCoins - SentCoins + OriginalVestingCoins - LockedCoins`
|
||||
## Glossary
|
||||
|
||||
Coins currently in Account:
|
||||
|
||||
`CurrentCoins = OriginalVestingCoins + ReceivedCoins - Delegated - Sent`
|
||||
|
||||
`CurrentCoins = vestingAccount.GetCoins()`
|
||||
|
||||
**Maximum amount of coins spendable right now:**
|
||||
|
||||
`min( ReceivedCoins - SentCoins + OriginalVestingCoins - LockedCoins, CurrentCoins )`
|
||||
- OriginalVesting: The amount of coins (per denomination) that are initially part of a vesting account. These coins are set at genesis.
|
||||
- StartTime: The BFT time at which a vesting account starts to vest.
|
||||
- EndTime: The BFT time at which a vesting account is fully vested.
|
||||
- DelegatedFree: The tracked amount of coins (per denomination) that are delegated from a vesting account that have been fully vested at time of delegation.
|
||||
- DelegatedVesting: The tracked amount of coins (per denomination) that are delegated from a vesting account that were vesting at time of delegation.
|
||||
- ContinuousVestingAccount: A vesting account implementation that vests coins linearly over time.
|
||||
- DelayedVestingAccount: A vesting account implementation that only fully vests all coins at a given time.
|
||||
|
|
|
@ -96,10 +96,12 @@ type Proposal struct {
|
|||
Type ProposalType // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
|
||||
Deposits []Deposit // List of deposits on the proposal
|
||||
SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included
|
||||
Submitter sdk.Address // Address of the submitter
|
||||
SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included
|
||||
DepositEndTime time.Time // Time that the DepositPeriod of a proposal would expire
|
||||
Submitter sdk.AccAddress // Address of the submitter
|
||||
|
||||
VotingStartTime time.Time // Time of the block where MinDeposit was reached. time.Time{} if MinDeposit is not reached
|
||||
VotingStartTime time.Time // Time of the block where MinDeposit was reached. time.Time{} if MinDeposit is not reached
|
||||
VotingEndTime time.Time // Time of the block that the VotingPeriod for a proposal will end.
|
||||
CurrentStatus ProposalStatus // Current status of the proposal
|
||||
|
||||
YesVotes sdk.Dec
|
||||
|
@ -134,46 +136,26 @@ For pseudocode purposes, here are the two function we will use to read or write
|
|||
|
||||
**Store:**
|
||||
* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the
|
||||
`ProposalIDs` of proposals that reached `MinDeposit`. Each round, the oldest
|
||||
element of `ProposalProcessingQueue` is checked during `BeginBlock` to see if
|
||||
`CurrentTime == VotingStartTime + activeProcedure.VotingPeriod`. If it is,
|
||||
then the application tallies the votes, compute the votes of each validator and checks if every validator in the valdiator set have voted
|
||||
and, if not, applies `GovernancePenalty`. If the proposal is accepted, deposits are refunded.
|
||||
After that proposal is ejected from `ProposalProcessingQueue` and the next element of the queue is evaluated.
|
||||
`ProposalIDs` of proposals that reached `MinDeposit`. Each `EndBlock`, all the proposals
|
||||
that have reached the end of their voting period are processed.
|
||||
To process a finished proposal, the application tallies the votes, compute the votes of
|
||||
each validator and checks if every validator in the valdiator set have voted.
|
||||
If the proposal is accepted, deposits are refunded.
|
||||
|
||||
And the pseudocode for the `ProposalProcessingQueue`:
|
||||
|
||||
```go
|
||||
in EndBlock do
|
||||
|
||||
checkProposal() // First call of the recursive function
|
||||
|
||||
|
||||
// Recursive function. First call in BeginBlock
|
||||
func checkProposal()
|
||||
proposalID = ProposalProcessingQueue.Peek()
|
||||
if (proposalID == nil)
|
||||
return
|
||||
for finishedProposalID in GetAllFinishedProposalIDs(block.Time)
|
||||
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
|
||||
|
||||
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
|
||||
votingProcedure = load(GlobalParams, 'VotingProcedure')
|
||||
validators = Keeper.getAllValidators()
|
||||
tmpValMap := map(sdk.AccAddress)ValidatorGovInfo
|
||||
|
||||
if (CurrentTime == proposal.VotingStartTime + votingProcedure.VotingPeriod && proposal.CurrentStatus == ProposalStatusActive)
|
||||
|
||||
// End of voting period, tally
|
||||
|
||||
ProposalProcessingQueue.pop()
|
||||
validators =
|
||||
|
||||
|
||||
Keeper.getAllValidators()
|
||||
tmpValMap := map(sdk.Address)ValidatorGovInfo
|
||||
|
||||
// Initiate mapping at 0. Validators that remain at 0 at the end of tally will be punished
|
||||
// Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes
|
||||
for each validator in validators
|
||||
tmpValMap(validator).Minus = 0
|
||||
|
||||
|
||||
tmpValMap(validator.OperatorAddr).Minus = 0
|
||||
|
||||
// Tally
|
||||
voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal
|
||||
|
@ -212,5 +194,4 @@ And the pseudocode for the `ProposalProcessingQueue`:
|
|||
proposal.CurrentStatus = ProposalStatusRejected
|
||||
|
||||
store(Governance, <proposalID|'proposal'>, proposal)
|
||||
checkProposal()
|
||||
```
|
||||
|
|
|
@ -45,6 +45,8 @@ upon receiving txGovSubmitProposal from sender do
|
|||
if (txGovSubmitProposal.Type != ProposalTypePlainText) OR (txGovSubmitProposal.Type != ProposalTypeSoftwareUpgrade)
|
||||
|
||||
sender.AtomBalance -= initialDeposit.Atoms
|
||||
|
||||
depositProcedure = load(GlobalParams, 'DepositProcedure')
|
||||
|
||||
proposalID = generate new proposalID
|
||||
proposal = NewProposal()
|
||||
|
@ -53,27 +55,15 @@ upon receiving txGovSubmitProposal from sender do
|
|||
proposal.Description = txGovSubmitProposal.Description
|
||||
proposal.Type = txGovSubmitProposal.Type
|
||||
proposal.TotalDeposit = initialDeposit
|
||||
proposal.SubmitBlock = CurrentBlock
|
||||
proposal.SubmitTime = <CurrentTime>
|
||||
proposal.DepositEndTime = <CurrentTime>.Add(depositProcedure.MaxDepositPeriod)
|
||||
proposal.Deposits.append({initialDeposit, sender})
|
||||
proposal.Submitter = sender
|
||||
proposal.YesVotes = 0
|
||||
proposal.NoVotes = 0
|
||||
proposal.NoWithVetoVotes = 0
|
||||
proposal.AbstainVotes = 0
|
||||
|
||||
depositProcedure = load(GlobalParams, 'DepositProcedure')
|
||||
|
||||
if (initialDeposit < depositProcedure.MinDeposit)
|
||||
// MinDeposit is not reached
|
||||
|
||||
proposal.CurrentStatus = ProposalStatusOpen
|
||||
|
||||
else
|
||||
// MinDeposit is reached
|
||||
|
||||
proposal.CurrentStatus = ProposalStatusActive
|
||||
proposal.VotingStartBlock = CurrentBlock
|
||||
ProposalProcessingQueue.push(proposalID)
|
||||
proposal.CurrentStatus = ProposalStatusOpen
|
||||
|
||||
store(Proposals, <proposalID|'proposal'>, proposal) // Store proposal in Proposals mapping
|
||||
return proposalID
|
||||
|
|
|
@ -7,7 +7,7 @@ The staking module allow for the following hooks to be registered with staking e
|
|||
type StakingHooks interface {
|
||||
OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created
|
||||
OnValidatorModified(ctx Context, address ValAddress) // Must be called when a validator's state changes
|
||||
OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted
|
||||
OnValidatorRemoved(ctx Context, address ConsAddress, operator ValAddress) // Must be called when a validator is deleted
|
||||
|
||||
OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded
|
||||
OnValidatorBeginUnbonding(ctx Context, address ConsAddress, operator ValAddress) // called when a validator begins unbonding
|
||||
|
|
|
@ -49,6 +49,8 @@ func main() {
|
|||
client.GetCommands(
|
||||
stakecmd.GetCmdQueryValidator("stake", cdc),
|
||||
stakecmd.GetCmdQueryValidators("stake", cdc),
|
||||
stakecmd.GetCmdQueryValidatorUnbondingDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryValidatorRedelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryPool("stake", cdc),
|
||||
|
|
|
@ -41,7 +41,6 @@ func main() {
|
|||
|
||||
appInit := server.DefaultAppInit
|
||||
rootCmd.AddCommand(InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
newApp, exportAppStateAndTMValidators)
|
||||
|
@ -85,7 +84,8 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, []json.RawMessage{genTx})
|
||||
appState, err := appInit.AppGenState(
|
||||
cdc, tmtypes.GenesisDoc{}, []json.RawMessage{genTx})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -108,13 +108,15 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID, []tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID,
|
||||
[]tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(client.FlagChainID, "",
|
||||
"genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(client.FlagName, "", "validator's moniker")
|
||||
cmd.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
|
@ -124,7 +126,8 @@ func newApp(logger log.Logger, db dbm.DB, storeTracer io.Writer) abci.Applicatio
|
|||
return app.NewBasecoinApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
|
||||
}
|
||||
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, storeTracer io.Writer) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, storeTracer io.Writer) (
|
||||
json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
bapp := app.NewBasecoinApp(logger, db)
|
||||
return bapp.ExportAppStateAndValidators()
|
||||
}
|
||||
|
|
|
@ -186,8 +186,8 @@ func (app *DemocoinApp) ExportAppStateAndValidators() (appState json.RawMessage,
|
|||
|
||||
genState := types.GenesisState{
|
||||
Accounts: accounts,
|
||||
POWGenesis: pow.WriteGenesis(ctx, app.powKeeper),
|
||||
CoolGenesis: cool.WriteGenesis(ctx, app.coolKeeper),
|
||||
POWGenesis: pow.ExportGenesis(ctx, app.powKeeper),
|
||||
CoolGenesis: cool.ExportGenesis(ctx, app.coolKeeper),
|
||||
}
|
||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
|
|
|
@ -21,6 +21,8 @@ import (
|
|||
coolcmd "github.com/cosmos/cosmos-sdk/examples/democoin/x/cool/client/cli"
|
||||
powcmd "github.com/cosmos/cosmos-sdk/examples/democoin/x/pow/client/cli"
|
||||
simplestakingcmd "github.com/cosmos/cosmos-sdk/examples/democoin/x/simplestake/client/cli"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
|
@ -38,6 +40,13 @@ func main() {
|
|||
// get the codec
|
||||
cdc := app.MakeCodec()
|
||||
|
||||
// Setup certain SDK config
|
||||
config := sdk.GetConfig()
|
||||
config.SetBech32PrefixForAccount("demoacc", "demopub")
|
||||
config.SetBech32PrefixForValidator("demoval", "demovalpub")
|
||||
config.SetBech32PrefixForConsensusNode("democons", "democonspub")
|
||||
config.Seal()
|
||||
|
||||
// TODO: setup keybase, viper object, etc. to be passed into
|
||||
// the below functions and eliminate global vars, like we do
|
||||
// with the cdc
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -35,8 +36,9 @@ var CoolAppInit = server.AppInit{
|
|||
}
|
||||
|
||||
// coolGenAppParams sets up the app_state and appends the cool app state
|
||||
func CoolAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
appState, err = server.SimpleAppGenState(cdc, appGenTxs)
|
||||
func CoolAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
appState json.RawMessage, err error) {
|
||||
appState, err = server.SimpleAppGenState(cdc, tmtypes.GenesisDoc{}, appGenTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -89,7 +91,8 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, []json.RawMessage{genTx})
|
||||
appState, err := appInit.AppGenState(cdc, tmtypes.GenesisDoc{},
|
||||
[]json.RawMessage{genTx})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -112,13 +115,15 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID, []tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
return gaiaInit.ExportGenesisFile(config.GenesisFile(), chainID,
|
||||
[]tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(client.FlagChainID, "",
|
||||
"genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(client.FlagName, "", "validator's moniker")
|
||||
cmd.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
|
@ -128,13 +133,22 @@ func newApp(logger log.Logger, db dbm.DB, _ io.Writer) abci.Application {
|
|||
return app.NewDemocoinApp(logger, db)
|
||||
}
|
||||
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, _ io.Writer) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, _ io.Writer) (
|
||||
json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
dapp := app.NewDemocoinApp(logger, db)
|
||||
return dapp.ExportAppStateAndValidators()
|
||||
}
|
||||
|
||||
func main() {
|
||||
cdc := app.MakeCodec()
|
||||
|
||||
// Setup certain SDK config
|
||||
config := sdk.GetConfig()
|
||||
config.SetBech32PrefixForAccount("demoacc", "demopub")
|
||||
config.SetBech32PrefixForValidator("demoval", "demovalpub")
|
||||
config.SetBech32PrefixForConsensusNode("democons", "democonspub")
|
||||
config.Seal()
|
||||
|
||||
ctx := server.NewDefaultContext()
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
|
|
|
@ -82,8 +82,13 @@ func (vs *ValidatorSet) IterateValidators(ctx sdk.Context, fn func(index int64,
|
|||
}
|
||||
}
|
||||
|
||||
// IterateValidatorsBonded implements sdk.ValidatorSet
|
||||
func (vs *ValidatorSet) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
|
||||
// IterateBondedValidatorsByPower implements sdk.ValidatorSet
|
||||
func (vs *ValidatorSet) IterateBondedValidatorsByPower(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
|
||||
vs.IterateValidators(ctx, fn)
|
||||
}
|
||||
|
||||
// IterateLastValidators implements sdk.ValidatorSet
|
||||
func (vs *ValidatorSet) IterateLastValidators(ctx sdk.Context, fn func(index int64, Validator sdk.Validator) bool) {
|
||||
vs.IterateValidators(ctx, fn)
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, data Genesis) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// WriteGenesis - output the genesis trend
|
||||
func WriteGenesis(ctx sdk.Context, k Keeper) Genesis {
|
||||
// ExportGenesis - output the genesis trend
|
||||
func ExportGenesis(ctx sdk.Context, k Keeper) Genesis {
|
||||
trend := k.GetTrend(ctx)
|
||||
return Genesis{trend}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ func TestCoolKeeper(t *testing.T) {
|
|||
err := InitGenesis(ctx, keeper, Genesis{"icy"})
|
||||
require.Nil(t, err)
|
||||
|
||||
genesis := WriteGenesis(ctx, keeper)
|
||||
genesis := ExportGenesis(ctx, keeper)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, genesis, Genesis{"icy"})
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ func (keeper Keeper) Info(ctx sdk.Context, p Payload) (res Info) {
|
|||
if bz == nil {
|
||||
return EmptyInfo(ctx)
|
||||
}
|
||||
keeper.cdc.MustUnmarshalBinary(bz, &res)
|
||||
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &res)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ func (keeper Keeper) setInfo(ctx sdk.Context, p Payload, info Info) {
|
|||
store := ctx.KVStore(keeper.key)
|
||||
|
||||
key := GetInfoKey(p, keeper.cdc)
|
||||
bz := keeper.cdc.MustMarshalBinary(info)
|
||||
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(info)
|
||||
store.Set(key, bz)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ import (
|
|||
|
||||
// GetInfoKey returns the key for OracleInfo
|
||||
func GetInfoKey(p Payload, cdc *codec.Codec) []byte {
|
||||
bz := cdc.MustMarshalBinary(p)
|
||||
bz := cdc.MustMarshalBinaryLengthPrefixed(p)
|
||||
return append([]byte{0x00}, bz...)
|
||||
}
|
||||
|
||||
// GetSignPrefix returns the prefix for signs
|
||||
func GetSignPrefix(p Payload, cdc *codec.Codec) []byte {
|
||||
bz := cdc.MustMarshalBinary(p)
|
||||
bz := cdc.MustMarshalBinaryLengthPrefixed(p)
|
||||
return append([]byte{0x01}, bz...)
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ func getSequence(ctx sdk.Context, key sdk.StoreKey) int {
|
|||
if seqbz == nil {
|
||||
seq = 0
|
||||
} else {
|
||||
codec.New().MustUnmarshalBinary(seqbz, &seq)
|
||||
codec.New().MustUnmarshalBinaryLengthPrefixed(seqbz, &seq)
|
||||
}
|
||||
|
||||
return seq
|
||||
|
@ -96,7 +96,7 @@ func handleSeqOracle(ctx sdk.Context, key sdk.StoreKey, o seqOracle) sdk.Error {
|
|||
return sdk.NewError(sdk.CodespaceRoot, 1, "")
|
||||
}
|
||||
|
||||
bz := codec.New().MustMarshalBinary(seq + 1)
|
||||
bz := codec.New().MustMarshalBinaryLengthPrefixed(seq + 1)
|
||||
store.Set([]byte("seq"), bz)
|
||||
|
||||
return nil
|
||||
|
|
|
@ -43,8 +43,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, genesis Genesis) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// WriteGenesis for the PoW module
|
||||
func WriteGenesis(ctx sdk.Context, k Keeper) Genesis {
|
||||
// ExportGenesis for the PoW module
|
||||
func ExportGenesis(ctx sdk.Context, k Keeper) Genesis {
|
||||
difficulty, err := k.GetLastDifficulty(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -41,7 +41,7 @@ func TestPowKeeperGetSet(t *testing.T) {
|
|||
err := InitGenesis(ctx, keeper, Genesis{uint64(1), uint64(0)})
|
||||
require.Nil(t, err)
|
||||
|
||||
genesis := WriteGenesis(ctx, keeper)
|
||||
genesis := ExportGenesis(ctx, keeper)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, genesis, Genesis{uint64(1), uint64(0)})
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ func (k Keeper) getBondInfo(ctx sdk.Context, addr sdk.AccAddress) bondInfo {
|
|||
return bondInfo{}
|
||||
}
|
||||
var bi bondInfo
|
||||
err := k.cdc.UnmarshalBinary(bz, &bi)
|
||||
err := k.cdc.UnmarshalBinaryLengthPrefixed(bz, &bi)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ func (k Keeper) getBondInfo(ctx sdk.Context, addr sdk.AccAddress) bondInfo {
|
|||
|
||||
func (k Keeper) setBondInfo(ctx sdk.Context, addr sdk.AccAddress, bi bondInfo) {
|
||||
store := ctx.KVStore(k.key)
|
||||
bz, err := k.cdc.MarshalBinary(bi)
|
||||
bz, err := k.cdc.MarshalBinaryLengthPrefixed(bi)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
seeds=(1 2 4 7 9 20 32 123 124 582 1893 2989 3012 4728 37827 981928 87821 891823782 989182 89182391)
|
||||
seeds=(1 2 4 7 9 20 32 123 124 582 1893 2989 3012 4728 37827 981928 87821 891823782 989182 89182391 \
|
||||
11 22 44 77 99 2020 3232 123123 124124 582582 18931893 29892989 30123012 47284728 37827)
|
||||
blocks=$1
|
||||
|
||||
echo "Running multi-seed simulation with seeds ${seeds[@]}"
|
||||
|
|
|
@ -19,7 +19,8 @@ import (
|
|||
type AppInit struct {
|
||||
// AppGenState creates the core parameters initialization. It takes in a
|
||||
// pubkey meant to represent the pubkey of the validator of this machine.
|
||||
AppGenState func(cdc *codec.Codec, appGenTx []json.RawMessage) (appState json.RawMessage, err error)
|
||||
AppGenState func(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
appState json.RawMessage, err error)
|
||||
}
|
||||
|
||||
// SimpleGenTx is a simple genesis tx
|
||||
|
@ -35,7 +36,8 @@ var DefaultAppInit = AppInit{
|
|||
}
|
||||
|
||||
// Generate a genesis transaction
|
||||
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (appGenTx, cliPrint json.RawMessage, validator types.GenesisValidator, err error) {
|
||||
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (
|
||||
appGenTx, cliPrint json.RawMessage, validator types.GenesisValidator, err error) {
|
||||
var addr sdk.AccAddress
|
||||
var secret string
|
||||
addr, secret, err = GenerateCoinKey()
|
||||
|
@ -63,7 +65,8 @@ func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (appGenTx, cliPrint json
|
|||
}
|
||||
|
||||
// create the genesis app state
|
||||
func SimpleAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
func SimpleAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
appState json.RawMessage, err error) {
|
||||
|
||||
if len(appGenTxs) != 1 {
|
||||
err = errors.New("must provide a single genesis transaction")
|
||||
|
|
|
@ -3,6 +3,7 @@ package mock
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"path/filepath"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
@ -102,7 +103,8 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci
|
|||
|
||||
// AppGenState can be passed into InitCmd, returns a static string of a few
|
||||
// key-values that can be parsed by InitChainer
|
||||
func AppGenState(_ *codec.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
func AppGenState(_ *codec.Codec, _ types.GenesisDoc, _ []json.RawMessage) (appState json.
|
||||
RawMessage, err error) {
|
||||
appState = json.RawMessage(`{
|
||||
"values": [
|
||||
{
|
||||
|
@ -119,7 +121,8 @@ func AppGenState(_ *codec.Codec, _ []json.RawMessage) (appState json.RawMessage,
|
|||
}
|
||||
|
||||
// AppGenStateEmpty returns an empty transaction state for mocking.
|
||||
func AppGenStateEmpty(_ *codec.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
func AppGenStateEmpty(_ *codec.Codec, _ types.GenesisDoc, _ []json.RawMessage) (
|
||||
appState json.RawMessage, err error) {
|
||||
appState = json.RawMessage(``)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package mock
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -20,7 +21,7 @@ func TestInitApp(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// initialize it future-way
|
||||
appState, err := AppGenState(nil, nil)
|
||||
appState, err := AppGenState(nil, types.GenesisDoc{}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
//TODO test validators in the init chain?
|
||||
|
|
|
@ -93,7 +93,6 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
|
||||
cfg := ctx.Config
|
||||
home := cfg.RootDir
|
||||
|
@ -135,7 +134,12 @@ func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// trap signal (run forever)
|
||||
tmNode.RunForever()
|
||||
return tmNode, nil
|
||||
TrapSignal(func() {
|
||||
if tmNode.IsRunning() {
|
||||
_ = tmNode.Stop()
|
||||
}
|
||||
})
|
||||
|
||||
// run forever (the node will not be returned)
|
||||
select {}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ import (
|
|||
"encoding/json"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -203,6 +205,23 @@ func ExternalIP() (string, error) {
|
|||
return "", errors.New("are you connected to the network?")
|
||||
}
|
||||
|
||||
// TrapSignal traps SIGINT and SIGTERM and terminates the server correctly.
|
||||
func TrapSignal(cleanupFunc func()) {
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
sig := <-sigs
|
||||
switch sig {
|
||||
case syscall.SIGTERM:
|
||||
defer cleanupFunc()
|
||||
os.Exit(128 + int(syscall.SIGTERM))
|
||||
case syscall.SIGINT:
|
||||
defer cleanupFunc()
|
||||
os.Exit(128 + int(syscall.SIGINT))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func skipInterface(iface net.Interface) bool {
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
return true // interface down
|
||||
|
|
|
@ -61,6 +61,7 @@ func (ci *cacheKVStore) Set(key []byte, value []byte) {
|
|||
ci.mtx.Lock()
|
||||
defer ci.mtx.Unlock()
|
||||
ci.assertValidKey(key)
|
||||
ci.assertValidValue(value)
|
||||
|
||||
ci.setCacheValue(key, value, false, true)
|
||||
}
|
||||
|
@ -196,6 +197,12 @@ func (ci *cacheKVStore) assertValidKey(key []byte) {
|
|||
}
|
||||
}
|
||||
|
||||
func (ci *cacheKVStore) assertValidValue(value []byte) {
|
||||
if value == nil {
|
||||
panic("value is nil")
|
||||
}
|
||||
}
|
||||
|
||||
// Only entrypoint to mutate ci.cache.
|
||||
func (ci *cacheKVStore) setCacheValue(key, value []byte, deleted bool, dirty bool) {
|
||||
ci.cache[string(key)] = cValue{
|
||||
|
|
|
@ -5,9 +5,9 @@ import (
|
|||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/iavl"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
|
||||
|
@ -210,44 +210,59 @@ func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
|||
res.Height = getHeight(tree, req)
|
||||
|
||||
switch req.Path {
|
||||
case "/store", "/key": // Get by key
|
||||
key := req.Data // Data holds the key bytes
|
||||
case "/key": // get by key
|
||||
key := req.Data // data holds the key bytes
|
||||
|
||||
res.Key = key
|
||||
if !st.VersionExists(res.Height) {
|
||||
res.Log = cmn.ErrorWrap(iavl.ErrVersionDoesNotExist, "").Error()
|
||||
break
|
||||
}
|
||||
|
||||
if req.Prove {
|
||||
value, proof, err := tree.GetVersionedWithProof(key, res.Height)
|
||||
if err != nil {
|
||||
res.Log = err.Error()
|
||||
break
|
||||
}
|
||||
res.Value = value
|
||||
cdc := amino.NewCodec()
|
||||
p, err := cdc.MarshalBinary(proof)
|
||||
if err != nil {
|
||||
res.Log = err.Error()
|
||||
break
|
||||
if proof == nil {
|
||||
// Proof == nil implies that the store is empty.
|
||||
if value != nil {
|
||||
panic("unexpected value for an empty proof")
|
||||
}
|
||||
}
|
||||
if value != nil {
|
||||
// value was found
|
||||
res.Value = value
|
||||
res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLValueOp(key, proof).ProofOp()}}
|
||||
} else {
|
||||
// value wasn't found
|
||||
res.Value = nil
|
||||
res.Proof = &merkle.Proof{Ops: []merkle.ProofOp{iavl.NewIAVLAbsenceOp(key, proof).ProofOp()}}
|
||||
}
|
||||
res.Proof = p
|
||||
} else {
|
||||
_, res.Value = tree.GetVersioned(key, res.Height)
|
||||
}
|
||||
|
||||
case "/subspace":
|
||||
var KVs []KVPair
|
||||
|
||||
subspace := req.Data
|
||||
res.Key = subspace
|
||||
var KVs []KVPair
|
||||
|
||||
iterator := sdk.KVStorePrefixIterator(st, subspace)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
KVs = append(KVs, KVPair{Key: iterator.Key(), Value: iterator.Value()})
|
||||
}
|
||||
|
||||
iterator.Close()
|
||||
res.Value = cdc.MustMarshalBinary(KVs)
|
||||
res.Value = cdc.MustMarshalBinaryLengthPrefixed(KVs)
|
||||
|
||||
default:
|
||||
msg := fmt.Sprintf("Unexpected Query path: %v", req.Path)
|
||||
return sdk.ErrUnknownRequest(msg).QueryResult()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -394,9 +394,9 @@ func TestIAVLStoreQuery(t *testing.T) {
|
|||
{Key: k1, Value: v3},
|
||||
{Key: k2, Value: v2},
|
||||
}
|
||||
valExpSubEmpty := cdc.MustMarshalBinary(KVs0)
|
||||
valExpSub1 := cdc.MustMarshalBinary(KVs1)
|
||||
valExpSub2 := cdc.MustMarshalBinary(KVs2)
|
||||
valExpSubEmpty := cdc.MustMarshalBinaryLengthPrefixed(KVs0)
|
||||
valExpSub1 := cdc.MustMarshalBinaryLengthPrefixed(KVs1)
|
||||
valExpSub2 := cdc.MustMarshalBinaryLengthPrefixed(KVs2)
|
||||
|
||||
cid := iavlStore.Commit()
|
||||
ver := cid.Version
|
||||
|
@ -459,7 +459,7 @@ func TestIAVLStoreQuery(t *testing.T) {
|
|||
require.Equal(t, valExpSub2, qres.Value)
|
||||
|
||||
// default (height 0) will show latest -1
|
||||
query0 := abci.RequestQuery{Path: "/store", Data: k1}
|
||||
query0 := abci.RequestQuery{Path: "/key", Data: k1}
|
||||
qres = iavlStore.Query(query0)
|
||||
require.Equal(t, uint32(sdk.CodeOK), qres.Code)
|
||||
require.Equal(t, v1, qres.Value)
|
||||
|
|
|
@ -42,21 +42,22 @@ func (m List) Len() (res uint64) {
|
|||
if bz == nil {
|
||||
return 0
|
||||
}
|
||||
m.cdc.MustUnmarshalBinary(bz, &res)
|
||||
|
||||
m.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &res)
|
||||
return
|
||||
}
|
||||
|
||||
// Get() returns the element by its index
|
||||
func (m List) Get(index uint64, ptr interface{}) error {
|
||||
bz := m.store.Get(ElemKey(index))
|
||||
return m.cdc.UnmarshalBinary(bz, ptr)
|
||||
return m.cdc.UnmarshalBinaryLengthPrefixed(bz, ptr)
|
||||
}
|
||||
|
||||
// Set() stores the element to the given position
|
||||
// Setting element out of range will break length counting
|
||||
// Use Push() instead of Set() to append a new element
|
||||
func (m List) Set(index uint64, value interface{}) {
|
||||
bz := m.cdc.MustMarshalBinary(value)
|
||||
bz := m.cdc.MustMarshalBinaryLengthPrefixed(value)
|
||||
m.store.Set(ElemKey(index), bz)
|
||||
}
|
||||
|
||||
|
@ -72,7 +73,7 @@ func (m List) Delete(index uint64) {
|
|||
func (m List) Push(value interface{}) {
|
||||
length := m.Len()
|
||||
m.Set(length, value)
|
||||
m.store.Set(LengthKey(), m.cdc.MustMarshalBinary(length+1))
|
||||
m.store.Set(LengthKey(), m.cdc.MustMarshalBinaryLengthPrefixed(length+1))
|
||||
}
|
||||
|
||||
// Iterate() is used to iterate over all existing elements in the list
|
||||
|
@ -85,13 +86,16 @@ func (m List) Iterate(ptr interface{}, fn func(uint64) bool) {
|
|||
iter := sdk.KVStorePrefixIterator(m.store, []byte{0x01})
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
v := iter.Value()
|
||||
m.cdc.MustUnmarshalBinary(v, ptr)
|
||||
m.cdc.MustUnmarshalBinaryLengthPrefixed(v, ptr)
|
||||
|
||||
k := iter.Key()
|
||||
s := string(k[len(k)-20:])
|
||||
|
||||
index, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if fn(index) {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -2,90 +2,139 @@ package store
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tendermint/iavl"
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
// MultiStoreProof defines a collection of store proofs in a multi-store
|
||||
type MultiStoreProof struct {
|
||||
StoreInfos []storeInfo
|
||||
StoreName string
|
||||
RangeProof iavl.RangeProof
|
||||
}
|
||||
|
||||
// buildMultiStoreProof build MultiStoreProof based on iavl proof and storeInfos
|
||||
func buildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) []byte {
|
||||
var rangeProof iavl.RangeProof
|
||||
cdc.MustUnmarshalBinary(iavlProof, &rangeProof)
|
||||
|
||||
msp := MultiStoreProof{
|
||||
StoreInfos: storeInfos,
|
||||
StoreName: storeName,
|
||||
RangeProof: rangeProof,
|
||||
}
|
||||
|
||||
proof := cdc.MustMarshalBinary(msp)
|
||||
return proof
|
||||
func NewMultiStoreProof(storeInfos []storeInfo) *MultiStoreProof {
|
||||
return &MultiStoreProof{StoreInfos: storeInfos}
|
||||
}
|
||||
|
||||
// VerifyMultiStoreCommitInfo verify multiStoreCommitInfo against appHash
|
||||
func VerifyMultiStoreCommitInfo(storeName string, storeInfos []storeInfo, appHash []byte) ([]byte, error) {
|
||||
var substoreCommitHash []byte
|
||||
var height int64
|
||||
for _, storeInfo := range storeInfos {
|
||||
if storeInfo.Name == storeName {
|
||||
substoreCommitHash = storeInfo.Core.CommitID.Hash
|
||||
height = storeInfo.Core.CommitID.Version
|
||||
}
|
||||
}
|
||||
if len(substoreCommitHash) == 0 {
|
||||
return nil, cmn.NewError("failed to get substore root commit hash by store name")
|
||||
}
|
||||
|
||||
// ComputeRootHash returns the root hash for a given multi-store proof.
|
||||
func (proof *MultiStoreProof) ComputeRootHash() []byte {
|
||||
ci := commitInfo{
|
||||
Version: height,
|
||||
StoreInfos: storeInfos,
|
||||
Version: -1, // TODO: Not needed; improve code.
|
||||
StoreInfos: proof.StoreInfos,
|
||||
}
|
||||
if !bytes.Equal(appHash, ci.Hash()) {
|
||||
return nil, cmn.NewError("the merkle root of multiStoreCommitInfo doesn't equal to appHash")
|
||||
}
|
||||
return substoreCommitHash, nil
|
||||
return ci.Hash()
|
||||
}
|
||||
|
||||
// VerifyRangeProof verify iavl RangeProof
|
||||
func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof *iavl.RangeProof) error {
|
||||
|
||||
// verify the proof to ensure data integrity.
|
||||
err := rangeProof.Verify(substoreCommitHash)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "proof root hash doesn't equal to substore commit root hash")
|
||||
}
|
||||
|
||||
if len(value) != 0 {
|
||||
// verify existence proof
|
||||
err = rangeProof.VerifyItem(key, value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed in existence verification")
|
||||
}
|
||||
} else {
|
||||
// verify absence proof
|
||||
err = rangeProof.VerifyAbsence(key)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed in absence verification")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RequireProof return whether proof is require for the subpath
|
||||
// RequireProof returns whether proof is required for the subpath.
|
||||
func RequireProof(subpath string) bool {
|
||||
// Currently, only when query subpath is "/store" or "/key", will proof be included in response.
|
||||
// If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go:212
|
||||
if subpath == "/store" || subpath == "/key" {
|
||||
// XXX: create a better convention.
|
||||
// Currently, only when query subpath is "/key", will proof be included in
|
||||
// response. If there are some changes about proof building in iavlstore.go,
|
||||
// we must change code here to keep consistency with iavlStore#Query.
|
||||
if subpath == "/key" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
var _ merkle.ProofOperator = MultiStoreProofOp{}
|
||||
|
||||
// the multi-store proof operation constant value
|
||||
const ProofOpMultiStore = "multistore"
|
||||
|
||||
// TODO: document
|
||||
type MultiStoreProofOp struct {
|
||||
// Encoded in ProofOp.Key
|
||||
key []byte
|
||||
|
||||
// To encode in ProofOp.Data.
|
||||
Proof *MultiStoreProof `json:"proof"`
|
||||
}
|
||||
|
||||
func NewMultiStoreProofOp(key []byte, proof *MultiStoreProof) MultiStoreProofOp {
|
||||
return MultiStoreProofOp{
|
||||
key: key,
|
||||
Proof: proof,
|
||||
}
|
||||
}
|
||||
|
||||
// MultiStoreProofOpDecoder returns a multi-store merkle proof operator from a
|
||||
// given proof operation.
|
||||
func MultiStoreProofOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) {
|
||||
if pop.Type != ProofOpMultiStore {
|
||||
return nil, cmn.NewError("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpMultiStore)
|
||||
}
|
||||
|
||||
// XXX: a bit strange as we'll discard this, but it works
|
||||
var op MultiStoreProofOp
|
||||
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(pop.Data, &op)
|
||||
if err != nil {
|
||||
return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data into MultiStoreProofOp")
|
||||
}
|
||||
|
||||
return NewMultiStoreProofOp(pop.Key, op.Proof), nil
|
||||
}
|
||||
|
||||
// ProofOp return a merkle proof operation from a given multi-store proof
|
||||
// operation.
|
||||
func (op MultiStoreProofOp) ProofOp() merkle.ProofOp {
|
||||
bz := cdc.MustMarshalBinaryLengthPrefixed(op)
|
||||
return merkle.ProofOp{
|
||||
Type: ProofOpMultiStore,
|
||||
Key: op.key,
|
||||
Data: bz,
|
||||
}
|
||||
}
|
||||
|
||||
// String implements the Stringer interface for a mult-store proof operation.
|
||||
func (op MultiStoreProofOp) String() string {
|
||||
return fmt.Sprintf("MultiStoreProofOp{%v}", op.GetKey())
|
||||
}
|
||||
|
||||
// GetKey returns the key for a multi-store proof operation.
|
||||
func (op MultiStoreProofOp) GetKey() []byte {
|
||||
return op.key
|
||||
}
|
||||
|
||||
// Run executes a multi-store proof operation for a given value. It returns
|
||||
// the root hash if the value matches all the store's commitID's hash or an
|
||||
// error otherwise.
|
||||
func (op MultiStoreProofOp) Run(args [][]byte) ([][]byte, error) {
|
||||
if len(args) != 1 {
|
||||
return nil, cmn.NewError("Value size is not 1")
|
||||
}
|
||||
|
||||
value := args[0]
|
||||
root := op.Proof.ComputeRootHash()
|
||||
|
||||
for _, si := range op.Proof.StoreInfos {
|
||||
if si.Name == string(op.key) {
|
||||
if bytes.Equal(value, si.Core.CommitID.Hash) {
|
||||
return [][]byte{root}, nil
|
||||
}
|
||||
|
||||
return nil, cmn.NewError("hash mismatch for substore %v: %X vs %X", si.Name, si.Core.CommitID.Hash, value)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, cmn.NewError("key %v not found in multistore proof", op.key)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// XXX: This should be managed by the rootMultiStore which may want to register
|
||||
// more proof ops?
|
||||
func DefaultProofRuntime() (prt *merkle.ProofRuntime) {
|
||||
prt = merkle.NewProofRuntime()
|
||||
prt.RegisterOpDecoder(merkle.ProofOpSimpleValue, merkle.SimpleValueOpDecoder)
|
||||
prt.RegisterOpDecoder(iavl.ProofOpIAVLValue, iavl.IAVLValueOpDecoder)
|
||||
prt.RegisterOpDecoder(iavl.ProofOpIAVLAbsence, iavl.IAVLAbsenceOpDecoder)
|
||||
prt.RegisterOpDecoder(ProofOpMultiStore, MultiStoreProofOpDecoder)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,123 +1,174 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/iavl"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/db"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
)
|
||||
|
||||
func TestVerifyMultiStoreCommitInfo(t *testing.T) {
|
||||
appHash, _ := hex.DecodeString("69959B1B4E68E0F7BD3551A50C8F849B81801AF2")
|
||||
|
||||
substoreRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828")
|
||||
storeName := "acc"
|
||||
|
||||
var storeInfos []storeInfo
|
||||
|
||||
gocRootHash, _ := hex.DecodeString("62c171bb022e47d1f745608ff749e676dbd25f78")
|
||||
storeInfos = append(storeInfos, storeInfo{
|
||||
Name: "gov",
|
||||
Core: storeCore{
|
||||
CommitID: CommitID{
|
||||
Version: 689,
|
||||
Hash: gocRootHash,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
storeInfos = append(storeInfos, storeInfo{
|
||||
Name: "main",
|
||||
Core: storeCore{
|
||||
CommitID: CommitID{
|
||||
Version: 689,
|
||||
Hash: nil,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
accRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828")
|
||||
storeInfos = append(storeInfos, storeInfo{
|
||||
Name: "acc",
|
||||
Core: storeCore{
|
||||
CommitID: CommitID{
|
||||
Version: 689,
|
||||
Hash: accRootHash,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
storeInfos = append(storeInfos, storeInfo{
|
||||
Name: "ibc",
|
||||
Core: storeCore{
|
||||
CommitID: CommitID{
|
||||
Version: 689,
|
||||
Hash: nil,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
stakeRootHash, _ := hex.DecodeString("987d1d27b8771d93aa3691262f661d2c85af7ca4")
|
||||
storeInfos = append(storeInfos, storeInfo{
|
||||
Name: "stake",
|
||||
Core: storeCore{
|
||||
CommitID: CommitID{
|
||||
Version: 689,
|
||||
Hash: stakeRootHash,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
slashingRootHash, _ := hex.DecodeString("388ee6e5b11f367069beb1eefd553491afe9d73e")
|
||||
storeInfos = append(storeInfos, storeInfo{
|
||||
Name: "slashing",
|
||||
Core: storeCore{
|
||||
CommitID: CommitID{
|
||||
Version: 689,
|
||||
Hash: slashingRootHash,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
commitHash, err := VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash)
|
||||
func TestVerifyIAVLStoreQueryProof(t *testing.T) {
|
||||
// Create main tree for testing.
|
||||
db := dbm.NewMemDB()
|
||||
iStore, err := LoadIAVLStore(db, CommitID{}, sdk.PruneNothing)
|
||||
store := iStore.(*iavlStore)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, commitHash, substoreRootHash)
|
||||
store.Set([]byte("MYKEY"), []byte("MYVALUE"))
|
||||
cid := store.Commit()
|
||||
|
||||
appHash, _ = hex.DecodeString("29de216bf5e2531c688de36caaf024cd3bb09ee3")
|
||||
// Get Proof
|
||||
res := store.Query(abci.RequestQuery{
|
||||
Path: "/key", // required path to get key/value+proof
|
||||
Data: []byte("MYKEY"),
|
||||
Prove: true,
|
||||
})
|
||||
require.NotNil(t, res.Proof)
|
||||
|
||||
_, err = VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash)
|
||||
require.Error(t, err, "appHash doesn't match to the merkle root of multiStoreCommitInfo")
|
||||
// Verify proof.
|
||||
prt := DefaultProofRuntime()
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/MYKEY", []byte("MYVALUE"))
|
||||
require.Nil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/MYKEY_NOT", []byte("MYVALUE"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/MYKEY/MYKEY", []byte("MYVALUE"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "MYKEY", []byte("MYVALUE"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/MYKEY", []byte("MYVALUE_NOT"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/MYKEY", []byte(nil))
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestVerifyRangeProof(t *testing.T) {
|
||||
tree := iavl.NewMutableTree(db.NewMemDB(), 0)
|
||||
func TestVerifyMultiStoreQueryProof(t *testing.T) {
|
||||
// Create main tree for testing.
|
||||
db := dbm.NewMemDB()
|
||||
store := NewCommitMultiStore(db)
|
||||
iavlStoreKey := sdk.NewKVStoreKey("iavlStoreKey")
|
||||
|
||||
rand := cmn.NewRand()
|
||||
rand.Seed(0) // for determinism
|
||||
for _, ikey := range []byte{0x11, 0x32, 0x50, 0x72, 0x99} {
|
||||
key := []byte{ikey}
|
||||
tree.Set(key, []byte(rand.Str(8)))
|
||||
}
|
||||
store.MountStoreWithDB(iavlStoreKey, sdk.StoreTypeIAVL, nil)
|
||||
store.LoadVersion(0)
|
||||
|
||||
root := tree.WorkingHash()
|
||||
iavlStore := store.GetCommitStore(iavlStoreKey).(*iavlStore)
|
||||
iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE"))
|
||||
cid := store.Commit()
|
||||
|
||||
key := []byte{0x32}
|
||||
val, proof, err := tree.GetWithProof(key)
|
||||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, val)
|
||||
assert.NotEmpty(t, proof)
|
||||
err = VerifyRangeProof(key, val, root, proof)
|
||||
assert.Nil(t, err)
|
||||
// Get Proof
|
||||
res := store.Query(abci.RequestQuery{
|
||||
Path: "/iavlStoreKey/key", // required path to get key/value+proof
|
||||
Data: []byte("MYKEY"),
|
||||
Prove: true,
|
||||
})
|
||||
require.NotNil(t, res.Proof)
|
||||
|
||||
key = []byte{0x40}
|
||||
val, proof, err = tree.GetWithProof(key)
|
||||
assert.Nil(t, err)
|
||||
assert.Empty(t, val)
|
||||
assert.NotEmpty(t, proof)
|
||||
err = VerifyRangeProof(key, val, root, proof)
|
||||
assert.Nil(t, err)
|
||||
// Verify proof.
|
||||
prt := DefaultProofRuntime()
|
||||
err := prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY", []byte("MYVALUE"))
|
||||
require.Nil(t, err)
|
||||
|
||||
// Verify proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY", []byte("MYVALUE"))
|
||||
require.Nil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY_NOT", []byte("MYVALUE"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY/MYKEY", []byte("MYVALUE"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "iavlStoreKey/MYKEY", []byte("MYVALUE"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/MYKEY", []byte("MYVALUE"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY", []byte("MYVALUE_NOT"))
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY", []byte(nil))
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestVerifyMultiStoreQueryProofEmptyStore(t *testing.T) {
|
||||
// Create main tree for testing.
|
||||
db := dbm.NewMemDB()
|
||||
store := NewCommitMultiStore(db)
|
||||
iavlStoreKey := sdk.NewKVStoreKey("iavlStoreKey")
|
||||
|
||||
store.MountStoreWithDB(iavlStoreKey, sdk.StoreTypeIAVL, nil)
|
||||
store.LoadVersion(0)
|
||||
cid := store.Commit() // Commit with empty iavl store.
|
||||
|
||||
// Get Proof
|
||||
res := store.Query(abci.RequestQuery{
|
||||
Path: "/iavlStoreKey/key", // required path to get key/value+proof
|
||||
Data: []byte("MYKEY"),
|
||||
Prove: true,
|
||||
})
|
||||
require.NotNil(t, res.Proof)
|
||||
|
||||
// Verify proof.
|
||||
prt := DefaultProofRuntime()
|
||||
err := prt.VerifyAbsence(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY")
|
||||
require.Nil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
prt = DefaultProofRuntime()
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYKEY", []byte("MYVALUE"))
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestVerifyMultiStoreQueryProofAbsence(t *testing.T) {
|
||||
// Create main tree for testing.
|
||||
db := dbm.NewMemDB()
|
||||
store := NewCommitMultiStore(db)
|
||||
iavlStoreKey := sdk.NewKVStoreKey("iavlStoreKey")
|
||||
|
||||
store.MountStoreWithDB(iavlStoreKey, sdk.StoreTypeIAVL, nil)
|
||||
store.LoadVersion(0)
|
||||
|
||||
iavlStore := store.GetCommitStore(iavlStoreKey).(*iavlStore)
|
||||
iavlStore.Set([]byte("MYKEY"), []byte("MYVALUE"))
|
||||
cid := store.Commit() // Commit with empty iavl store.
|
||||
|
||||
// Get Proof
|
||||
res := store.Query(abci.RequestQuery{
|
||||
Path: "/iavlStoreKey/key", // required path to get key/value+proof
|
||||
Data: []byte("MYABSENTKEY"),
|
||||
Prove: true,
|
||||
})
|
||||
require.NotNil(t, res.Proof)
|
||||
|
||||
// Verify proof.
|
||||
prt := DefaultProofRuntime()
|
||||
err := prt.VerifyAbsence(res.Proof, cid.Hash, "/iavlStoreKey/MYABSENTKEY")
|
||||
require.Nil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
prt = DefaultProofRuntime()
|
||||
err = prt.VerifyAbsence(res.Proof, cid.Hash, "/MYABSENTKEY")
|
||||
require.NotNil(t, err)
|
||||
|
||||
// Verify (bad) proof.
|
||||
prt = DefaultProofRuntime()
|
||||
err = prt.VerifyValue(res.Proof, cid.Hash, "/iavlStoreKey/MYABSENTKEY", []byte(""))
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
|
|
@ -27,12 +27,12 @@ func (m Queue) getTop() (res uint64) {
|
|||
return 0
|
||||
}
|
||||
|
||||
m.List.cdc.MustUnmarshalBinary(bz, &res)
|
||||
m.List.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &res)
|
||||
return
|
||||
}
|
||||
|
||||
func (m Queue) setTop(top uint64) {
|
||||
bz := m.List.cdc.MustMarshalBinary(top)
|
||||
bz := m.List.cdc.MustMarshalBinaryLengthPrefixed(top)
|
||||
m.List.store.Set(TopKey(), bz)
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ func TestKeys(t *testing.T) {
|
|||
var actual int
|
||||
|
||||
// Checking keys.LengthKey
|
||||
err := cdc.UnmarshalBinary(store.Get(LengthKey()), &len)
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(store.Get(LengthKey()), &len)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, len, queue.List.Len())
|
||||
|
||||
|
@ -89,14 +89,14 @@ func TestKeys(t *testing.T) {
|
|||
for i := 0; i < 10; i++ {
|
||||
queue.List.Get(uint64(i), &expected)
|
||||
bz := store.Get(ElemKey(uint64(i)))
|
||||
err = cdc.UnmarshalBinary(bz, &actual)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(bz, &actual)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
queue.Pop()
|
||||
|
||||
err = cdc.UnmarshalBinary(store.Get(TopKey()), &top)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(store.Get(TopKey()), &top)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, top, queue.getTop())
|
||||
}
|
||||
|
|
|
@ -295,13 +295,23 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery {
|
|||
return res
|
||||
}
|
||||
|
||||
if res.Proof == nil || len(res.Proof.Ops) == 0 {
|
||||
return sdk.ErrInternal("substore proof was nil/empty when it should never be").QueryResult()
|
||||
}
|
||||
|
||||
commitInfo, errMsg := getCommitInfo(rs.db, res.Height)
|
||||
if errMsg != nil {
|
||||
return sdk.ErrInternal(errMsg.Error()).QueryResult()
|
||||
}
|
||||
|
||||
res.Proof = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos)
|
||||
// Restore origin path and append proof op.
|
||||
res.Proof.Ops = append(res.Proof.Ops, NewMultiStoreProofOp(
|
||||
[]byte(storeName),
|
||||
NewMultiStoreProof(commitInfo.StoreInfos),
|
||||
).ProofOp())
|
||||
|
||||
// TODO: handle in another TM v0.26 update PR
|
||||
// res.Proof = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos)
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -313,11 +323,14 @@ func parsePath(path string) (storeName string, subpath string, err sdk.Error) {
|
|||
err = sdk.ErrUnknownRequest(fmt.Sprintf("invalid path: %s", path))
|
||||
return
|
||||
}
|
||||
|
||||
paths := strings.SplitN(path[1:], "/", 2)
|
||||
storeName = paths[0]
|
||||
|
||||
if len(paths) == 2 {
|
||||
subpath = "/" + paths[1]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -386,11 +399,12 @@ type commitInfo struct {
|
|||
|
||||
// Hash returns the simple merkle root hash of the stores sorted by name.
|
||||
func (ci commitInfo) Hash() []byte {
|
||||
// TODO cache to ci.hash []byte
|
||||
m := make(map[string]merkle.Hasher, len(ci.StoreInfos))
|
||||
// TODO: cache to ci.hash []byte
|
||||
m := make(map[string][]byte, len(ci.StoreInfos))
|
||||
for _, storeInfo := range ci.StoreInfos {
|
||||
m[storeInfo.Name] = storeInfo
|
||||
m[storeInfo.Name] = storeInfo.Hash()
|
||||
}
|
||||
|
||||
return merkle.SimpleHashFromMap(m)
|
||||
}
|
||||
|
||||
|
@ -422,13 +436,15 @@ type storeCore struct {
|
|||
func (si storeInfo) Hash() []byte {
|
||||
// Doesn't write Name, since merkle.SimpleHashFromMap() will
|
||||
// include them via the keys.
|
||||
bz, _ := cdc.MarshalBinary(si.Core) // Does not error
|
||||
bz, _ := cdc.MarshalBinaryLengthPrefixed(si.Core)
|
||||
hasher := tmhash.New()
|
||||
|
||||
_, err := hasher.Write(bz)
|
||||
if err != nil {
|
||||
// TODO: Handle with #870
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return hasher.Sum(nil)
|
||||
}
|
||||
|
||||
|
@ -441,16 +457,18 @@ func getLatestVersion(db dbm.DB) int64 {
|
|||
if latestBytes == nil {
|
||||
return 0
|
||||
}
|
||||
err := cdc.UnmarshalBinary(latestBytes, &latest)
|
||||
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(latestBytes, &latest)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return latest
|
||||
}
|
||||
|
||||
// Set the latest version.
|
||||
func setLatestVersion(batch dbm.Batch, version int64) {
|
||||
latestBytes, _ := cdc.MarshalBinary(version) // Does not error
|
||||
latestBytes, _ := cdc.MarshalBinaryLengthPrefixed(version)
|
||||
batch.Set([]byte(latestVersionKey), latestBytes)
|
||||
}
|
||||
|
||||
|
@ -491,21 +509,19 @@ func getCommitInfo(db dbm.DB, ver int64) (commitInfo, error) {
|
|||
return commitInfo{}, fmt.Errorf("failed to get rootMultiStore: no data")
|
||||
}
|
||||
|
||||
// Parse bytes.
|
||||
var cInfo commitInfo
|
||||
err := cdc.UnmarshalBinary(cInfoBytes, &cInfo)
|
||||
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(cInfoBytes, &cInfo)
|
||||
if err != nil {
|
||||
return commitInfo{}, fmt.Errorf("failed to get rootMultiStore: %v", err)
|
||||
}
|
||||
|
||||
return cInfo, nil
|
||||
}
|
||||
|
||||
// Set a commitInfo for given version.
|
||||
func setCommitInfo(batch dbm.Batch, version int64, cInfo commitInfo) {
|
||||
cInfoBytes, err := cdc.MarshalBinary(cInfo)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cInfoBytes := cdc.MustMarshalBinaryLengthPrefixed(cInfo)
|
||||
cInfoKey := fmt.Sprintf(commitInfoKeyFmt, version)
|
||||
batch.Set([]byte(cInfoKey), cInfoBytes)
|
||||
}
|
||||
|
|
|
@ -215,7 +215,7 @@ func getExpectedCommitID(store *rootMultiStore, ver int64) CommitID {
|
|||
}
|
||||
|
||||
func hashStores(stores map[StoreKey]CommitStore) []byte {
|
||||
m := make(map[string]merkle.Hasher, len(stores))
|
||||
m := make(map[string][]byte, len(stores))
|
||||
for key, store := range stores {
|
||||
name := key.Name()
|
||||
m[name] = storeInfo{
|
||||
|
@ -224,7 +224,7 @@ func hashStores(stores map[StoreKey]CommitStore) []byte {
|
|||
CommitID: store.LastCommitID(),
|
||||
// StoreType: store.GetStoreType(),
|
||||
},
|
||||
}
|
||||
}.Hash()
|
||||
}
|
||||
return merkle.SimpleHashFromMap(m)
|
||||
}
|
||||
|
|
|
@ -55,7 +55,8 @@ func AccAddressFromHex(address string) (addr AccAddress, err error) {
|
|||
|
||||
// AccAddressFromBech32 creates an AccAddress from a Bech32 string.
|
||||
func AccAddressFromBech32(address string) (addr AccAddress, err error) {
|
||||
bz, err := GetFromBech32(address, Bech32PrefixAccAddr)
|
||||
bech32PrefixAccAddr := GetConfig().GetBech32AccountAddrPrefix()
|
||||
bz, err := GetFromBech32(address, bech32PrefixAccAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -124,7 +125,8 @@ func (aa AccAddress) Bytes() []byte {
|
|||
|
||||
// String implements the Stringer interface.
|
||||
func (aa AccAddress) String() string {
|
||||
bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixAccAddr, aa.Bytes())
|
||||
bech32PrefixAccAddr := GetConfig().GetBech32AccountAddrPrefix()
|
||||
bech32Addr, err := bech32.ConvertAndEncode(bech32PrefixAccAddr, aa.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -169,7 +171,8 @@ func ValAddressFromHex(address string) (addr ValAddress, err error) {
|
|||
|
||||
// ValAddressFromBech32 creates a ValAddress from a Bech32 string.
|
||||
func ValAddressFromBech32(address string) (addr ValAddress, err error) {
|
||||
bz, err := GetFromBech32(address, Bech32PrefixValAddr)
|
||||
bech32PrefixValAddr := GetConfig().GetBech32ValidatorAddrPrefix()
|
||||
bz, err := GetFromBech32(address, bech32PrefixValAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -239,7 +242,8 @@ func (va ValAddress) Bytes() []byte {
|
|||
|
||||
// String implements the Stringer interface.
|
||||
func (va ValAddress) String() string {
|
||||
bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixValAddr, va.Bytes())
|
||||
bech32PrefixValAddr := GetConfig().GetBech32ValidatorAddrPrefix()
|
||||
bech32Addr, err := bech32.ConvertAndEncode(bech32PrefixValAddr, va.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -284,7 +288,8 @@ func ConsAddressFromHex(address string) (addr ConsAddress, err error) {
|
|||
|
||||
// ConsAddressFromBech32 creates a ConsAddress from a Bech32 string.
|
||||
func ConsAddressFromBech32(address string) (addr ConsAddress, err error) {
|
||||
bz, err := GetFromBech32(address, Bech32PrefixConsAddr)
|
||||
bech32PrefixConsAddr := GetConfig().GetBech32ConsensusAddrPrefix()
|
||||
bz, err := GetFromBech32(address, bech32PrefixConsAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -359,7 +364,8 @@ func (ca ConsAddress) Bytes() []byte {
|
|||
|
||||
// String implements the Stringer interface.
|
||||
func (ca ConsAddress) String() string {
|
||||
bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixConsAddr, ca.Bytes())
|
||||
bech32PrefixConsAddr := GetConfig().GetBech32ConsensusAddrPrefix()
|
||||
bech32Addr, err := bech32.ConvertAndEncode(bech32PrefixConsAddr, ca.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -387,7 +393,8 @@ func (ca ConsAddress) Format(s fmt.State, verb rune) {
|
|||
// Bech32ifyAccPub returns a Bech32 encoded string containing the
|
||||
// Bech32PrefixAccPub prefix for a given account PubKey.
|
||||
func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
|
||||
return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
|
||||
bech32PrefixAccPub := GetConfig().GetBech32AccountPubPrefix()
|
||||
return bech32.ConvertAndEncode(bech32PrefixAccPub, pub.Bytes())
|
||||
}
|
||||
|
||||
// MustBech32ifyAccPub returns the result of Bech32ifyAccPub panicing on failure.
|
||||
|
@ -403,7 +410,8 @@ func MustBech32ifyAccPub(pub crypto.PubKey) string {
|
|||
// Bech32ifyValPub returns a Bech32 encoded string containing the
|
||||
// Bech32PrefixValPub prefix for a given validator operator's PubKey.
|
||||
func Bech32ifyValPub(pub crypto.PubKey) (string, error) {
|
||||
return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
|
||||
bech32PrefixValPub := GetConfig().GetBech32ValidatorPubPrefix()
|
||||
return bech32.ConvertAndEncode(bech32PrefixValPub, pub.Bytes())
|
||||
}
|
||||
|
||||
// MustBech32ifyValPub returns the result of Bech32ifyValPub panicing on failure.
|
||||
|
@ -419,7 +427,8 @@ func MustBech32ifyValPub(pub crypto.PubKey) string {
|
|||
// Bech32ifyConsPub returns a Bech32 encoded string containing the
|
||||
// Bech32PrefixConsPub prefixfor a given consensus node's PubKey.
|
||||
func Bech32ifyConsPub(pub crypto.PubKey) (string, error) {
|
||||
return bech32.ConvertAndEncode(Bech32PrefixConsPub, pub.Bytes())
|
||||
bech32PrefixConsPub := GetConfig().GetBech32ConsensusPubPrefix()
|
||||
return bech32.ConvertAndEncode(bech32PrefixConsPub, pub.Bytes())
|
||||
}
|
||||
|
||||
// MustBech32ifyConsPub returns the result of Bech32ifyConsPub panicing on
|
||||
|
@ -436,7 +445,8 @@ func MustBech32ifyConsPub(pub crypto.PubKey) string {
|
|||
// GetAccPubKeyBech32 creates a PubKey for an account with a given public key
|
||||
// string using the Bech32 Bech32PrefixAccPub prefix.
|
||||
func GetAccPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
|
||||
bz, err := GetFromBech32(pubkey, Bech32PrefixAccPub)
|
||||
bech32PrefixAccPub := GetConfig().GetBech32AccountPubPrefix()
|
||||
bz, err := GetFromBech32(pubkey, bech32PrefixAccPub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -463,7 +473,8 @@ func MustGetAccPubKeyBech32(pubkey string) (pk crypto.PubKey) {
|
|||
// GetValPubKeyBech32 creates a PubKey for a validator's operator with a given
|
||||
// public key string using the Bech32 Bech32PrefixValPub prefix.
|
||||
func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
|
||||
bz, err := GetFromBech32(pubkey, Bech32PrefixValPub)
|
||||
bech32PrefixValPub := GetConfig().GetBech32ValidatorPubPrefix()
|
||||
bz, err := GetFromBech32(pubkey, bech32PrefixValPub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -490,7 +501,8 @@ func MustGetValPubKeyBech32(pubkey string) (pk crypto.PubKey) {
|
|||
// GetConsPubKeyBech32 creates a PubKey for a consensus node with a given public
|
||||
// key string using the Bech32 Bech32PrefixConsPub prefix.
|
||||
func GetConsPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
|
||||
bz, err := GetFromBech32(pubkey, Bech32PrefixConsPub)
|
||||
bech32PrefixConsPub := GetConfig().GetBech32ConsensusPubPrefix()
|
||||
bz, err := GetFromBech32(pubkey, bech32PrefixConsPub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
|
@ -178,3 +180,44 @@ func TestConsAddress(t *testing.T) {
|
|||
require.NotNil(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
const letterBytes = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
func RandString(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func TestConfiguredPrefix(t *testing.T) {
|
||||
var pub ed25519.PubKeyEd25519
|
||||
for length := 1; length < 10; length++ {
|
||||
for times := 1; times < 20; times++ {
|
||||
rand.Read(pub[:])
|
||||
// Test if randomly generated prefix of a given length works
|
||||
prefix := RandString(length)
|
||||
// Assuming that GetConfig is not sealed.
|
||||
config := types.GetConfig()
|
||||
config.SetBech32PrefixForAccount(prefix+"acc", prefix+"pub")
|
||||
acc := types.AccAddress(pub.Address())
|
||||
require.True(t, strings.HasPrefix(acc.String(), prefix+"acc"))
|
||||
bech32Pub := types.MustBech32ifyAccPub(pub)
|
||||
require.True(t, strings.HasPrefix(bech32Pub, prefix+"pub"))
|
||||
|
||||
config.SetBech32PrefixForValidator(prefix+"valaddr", prefix+"valpub")
|
||||
val := types.ValAddress(pub.Address())
|
||||
require.True(t, strings.HasPrefix(val.String(), prefix+"valaddr"))
|
||||
bech32ValPub := types.MustBech32ifyValPub(pub)
|
||||
require.True(t, strings.HasPrefix(bech32ValPub, prefix+"valpub"))
|
||||
|
||||
config.SetBech32PrefixForConsensusNode(prefix+"consaddr", prefix+"conspub")
|
||||
cons := types.ConsAddress(pub.Address())
|
||||
require.True(t, strings.HasPrefix(cons.String(), prefix+"consaddr"))
|
||||
bech32ConsPub := types.MustBech32ifyConsPub(pub)
|
||||
require.True(t, strings.HasPrefix(bech32ConsPub, prefix+"conspub"))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ func (coin Coin) IsGTE(other Coin) bool {
|
|||
// IsLT returns true if they are the same type and the receiver is
|
||||
// a smaller value
|
||||
func (coin Coin) IsLT(other Coin) bool {
|
||||
return !coin.IsGTE(other)
|
||||
return coin.SameDenomAs(other) && coin.Amount.LT(other.Amount)
|
||||
}
|
||||
|
||||
// IsEqual returns true if the two sets of Coins have the same value
|
||||
|
@ -142,7 +142,11 @@ func (coins Coins) Plus(coinsB Coins) Coins {
|
|||
coinA, coinB := coins[indexA], coinsB[indexB]
|
||||
switch strings.Compare(coinA.Denom, coinB.Denom) {
|
||||
case -1:
|
||||
sum = append(sum, coinA)
|
||||
if coinA.IsZero() {
|
||||
// ignore 0 sum coin type
|
||||
} else {
|
||||
sum = append(sum, coinA)
|
||||
}
|
||||
indexA++
|
||||
case 0:
|
||||
if coinA.Amount.Add(coinB.Amount).IsZero() {
|
||||
|
@ -153,7 +157,11 @@ func (coins Coins) Plus(coinsB Coins) Coins {
|
|||
indexA++
|
||||
indexB++
|
||||
case 1:
|
||||
sum = append(sum, coinB)
|
||||
if coinB.IsZero() {
|
||||
// ignore 0 sum coin type
|
||||
} else {
|
||||
sum = append(sum, coinB)
|
||||
}
|
||||
indexB++
|
||||
}
|
||||
}
|
||||
|
@ -176,10 +184,19 @@ func (coins Coins) Minus(coinsB Coins) Coins {
|
|||
return coins.Plus(coinsB.Negative())
|
||||
}
|
||||
|
||||
// IsGTE returns True iff coins is NonNegative(), and for every
|
||||
// currency in coinsB, the currency is present at an equal or greater
|
||||
// amount in coinsB
|
||||
func (coins Coins) IsGTE(coinsB Coins) bool {
|
||||
// IsAllGT returns True iff for every denom in coins, the denom is present at a
|
||||
// greater amount in coinsB.
|
||||
func (coins Coins) IsAllGT(coinsB Coins) bool {
|
||||
diff := coins.Minus(coinsB)
|
||||
if len(diff) == 0 {
|
||||
return false
|
||||
}
|
||||
return diff.IsPositive()
|
||||
}
|
||||
|
||||
// IsAllGTE returns True iff for every denom in coins, the denom is present at an
|
||||
// equal or greater amount in coinsB.
|
||||
func (coins Coins) IsAllGTE(coinsB Coins) bool {
|
||||
diff := coins.Minus(coinsB)
|
||||
if len(diff) == 0 {
|
||||
return true
|
||||
|
@ -187,14 +204,27 @@ func (coins Coins) IsGTE(coinsB Coins) bool {
|
|||
return diff.IsNotNegative()
|
||||
}
|
||||
|
||||
// IsLT returns True iff every currency in coins, the currency is
|
||||
// present at a smaller amount in coins
|
||||
func (coins Coins) IsLT(coinsB Coins) bool {
|
||||
return !coins.IsGTE(coinsB)
|
||||
// IsAllLT returns True iff for every denom in coins, the denom is present at
|
||||
// a smaller amount in coinsB.
|
||||
func (coins Coins) IsAllLT(coinsB Coins) bool {
|
||||
diff := coinsB.Minus(coins)
|
||||
if len(diff) == 0 {
|
||||
return false
|
||||
}
|
||||
return diff.IsPositive()
|
||||
}
|
||||
|
||||
// IsZero returns true if there are no coins
|
||||
// or all coins are zero.
|
||||
// IsAllLTE returns True iff for every denom in coins, the denom is present at
|
||||
// a smaller or equal amount in coinsB.
|
||||
func (coins Coins) IsAllLTE(coinsB Coins) bool {
|
||||
diff := coinsB.Minus(coins)
|
||||
if len(diff) == 0 {
|
||||
return true
|
||||
}
|
||||
return diff.IsNotNegative()
|
||||
}
|
||||
|
||||
// IsZero returns true if there are no coins or all coins are zero.
|
||||
func (coins Coins) IsZero() bool {
|
||||
for _, coin := range coins {
|
||||
if !coin.IsZero() {
|
||||
|
|
|
@ -86,7 +86,10 @@ func TestIsLTCoin(t *testing.T) {
|
|||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), false},
|
||||
{NewInt64Coin("A", 2), NewInt64Coin("A", 1), false},
|
||||
{NewInt64Coin("A", -1), NewInt64Coin("A", 5), true},
|
||||
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), true},
|
||||
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), false},
|
||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
||||
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), false},
|
||||
{NewInt64Coin("a", 1), NewInt64Coin("a", 2), true},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range cases {
|
||||
|
@ -245,9 +248,9 @@ func TestCoins(t *testing.T) {
|
|||
assert.True(t, good.IsValid(), "Coins are valid")
|
||||
assert.True(t, good.IsPositive(), "Expected coins to be positive: %v", good)
|
||||
assert.False(t, null.IsPositive(), "Expected coins to not be positive: %v", null)
|
||||
assert.True(t, good.IsGTE(empty), "Expected %v to be >= %v", good, empty)
|
||||
assert.False(t, good.IsLT(empty), "Expected %v to be < %v", good, empty)
|
||||
assert.True(t, empty.IsLT(good), "Expected %v to be < %v", empty, good)
|
||||
assert.True(t, good.IsAllGTE(empty), "Expected %v to be >= %v", good, empty)
|
||||
assert.False(t, good.IsAllLT(empty), "Expected %v to be < %v", good, empty)
|
||||
assert.True(t, empty.IsAllLT(good), "Expected %v to be < %v", empty, good)
|
||||
assert.False(t, neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
|
||||
assert.Zero(t, len(sum), "Expected 0 coins")
|
||||
assert.False(t, badSort1.IsValid(), "Coins are not sorted")
|
||||
|
@ -257,6 +260,60 @@ func TestCoins(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestCoinsGT(t *testing.T) {
|
||||
one := NewInt(1)
|
||||
two := NewInt(2)
|
||||
|
||||
assert.False(t, Coins{}.IsAllGT(Coins{}))
|
||||
assert.True(t, Coins{{"A", one}}.IsAllGT(Coins{}))
|
||||
assert.False(t, Coins{{"A", one}}.IsAllGT(Coins{{"A", one}}))
|
||||
assert.False(t, Coins{{"A", one}}.IsAllGT(Coins{{"B", one}}))
|
||||
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllGT(Coins{{"B", one}}))
|
||||
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllGT(Coins{{"B", two}}))
|
||||
}
|
||||
|
||||
func TestCoinsGTE(t *testing.T) {
|
||||
one := NewInt(1)
|
||||
two := NewInt(2)
|
||||
|
||||
assert.True(t, Coins{}.IsAllGTE(Coins{}))
|
||||
assert.True(t, Coins{{"A", one}}.IsAllGTE(Coins{}))
|
||||
assert.True(t, Coins{{"A", one}}.IsAllGTE(Coins{{"A", one}}))
|
||||
assert.False(t, Coins{{"A", one}}.IsAllGTE(Coins{{"B", one}}))
|
||||
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllGTE(Coins{{"B", one}}))
|
||||
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllGTE(Coins{{"B", two}}))
|
||||
}
|
||||
|
||||
func TestCoinsLT(t *testing.T) {
|
||||
one := NewInt(1)
|
||||
two := NewInt(2)
|
||||
|
||||
assert.False(t, Coins{}.IsAllLT(Coins{}))
|
||||
assert.False(t, Coins{{"A", one}}.IsAllLT(Coins{}))
|
||||
assert.False(t, Coins{{"A", one}}.IsAllLT(Coins{{"A", one}}))
|
||||
assert.False(t, Coins{{"A", one}}.IsAllLT(Coins{{"B", one}}))
|
||||
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLT(Coins{{"B", one}}))
|
||||
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLT(Coins{{"B", two}}))
|
||||
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLT(Coins{{"A", one}, {"B", one}}))
|
||||
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllLT(Coins{{"A", one}, {"B", two}}))
|
||||
assert.True(t, Coins{}.IsAllLT(Coins{{"A", one}}))
|
||||
}
|
||||
|
||||
func TestCoinsLTE(t *testing.T) {
|
||||
one := NewInt(1)
|
||||
two := NewInt(2)
|
||||
|
||||
assert.True(t, Coins{}.IsAllLTE(Coins{}))
|
||||
assert.False(t, Coins{{"A", one}}.IsAllLTE(Coins{}))
|
||||
assert.True(t, Coins{{"A", one}}.IsAllLTE(Coins{{"A", one}}))
|
||||
assert.False(t, Coins{{"A", one}}.IsAllLTE(Coins{{"B", one}}))
|
||||
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLTE(Coins{{"B", one}}))
|
||||
assert.False(t, Coins{{"A", one}, {"B", one}}.IsAllLTE(Coins{{"B", two}}))
|
||||
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllLTE(Coins{{"A", one}, {"B", one}}))
|
||||
assert.True(t, Coins{{"A", one}, {"B", one}}.IsAllLTE(Coins{{"A", one}, {"B", two}}))
|
||||
assert.True(t, Coins{}.IsAllLTE(Coins{{"A", one}}))
|
||||
}
|
||||
|
||||
func TestPlusCoins(t *testing.T) {
|
||||
one := NewInt(1)
|
||||
zero := NewInt(0)
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Config is the structure that holds the SDK configuration parameters.
|
||||
// This could be used to initialize certain configuration parameters for the SDK.
|
||||
type Config struct {
|
||||
mtx sync.RWMutex
|
||||
sealed bool
|
||||
bech32AddressPrefix map[string]string
|
||||
}
|
||||
|
||||
var (
|
||||
// Initializing an instance of Config
|
||||
sdkConfig = &Config{
|
||||
sealed: false,
|
||||
bech32AddressPrefix: map[string]string{
|
||||
"account_addr": Bech32PrefixAccAddr,
|
||||
"validator_addr": Bech32PrefixValAddr,
|
||||
"consensus_addr": Bech32PrefixConsAddr,
|
||||
"account_pub": Bech32PrefixAccPub,
|
||||
"validator_pub": Bech32PrefixValPub,
|
||||
"consensus_pub": Bech32PrefixConsPub,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// GetConfig returns the config instance for the SDK.
|
||||
func GetConfig() *Config {
|
||||
return sdkConfig
|
||||
}
|
||||
|
||||
func (config *Config) assertNotSealed() {
|
||||
config.mtx.Lock()
|
||||
defer config.mtx.Unlock()
|
||||
|
||||
if config.sealed {
|
||||
panic("Config is sealed")
|
||||
}
|
||||
}
|
||||
|
||||
// SetBech32PrefixForAccount builds the Config with Bech32 addressPrefix and publKeyPrefix for accounts
|
||||
// and returns the config instance
|
||||
func (config *Config) SetBech32PrefixForAccount(addressPrefix, pubKeyPrefix string) {
|
||||
config.assertNotSealed()
|
||||
config.bech32AddressPrefix["account_addr"] = addressPrefix
|
||||
config.bech32AddressPrefix["account_pub"] = pubKeyPrefix
|
||||
}
|
||||
|
||||
// SetBech32PrefixForValidator builds the Config with Bech32 addressPrefix and publKeyPrefix for validators
|
||||
// and returns the config instance
|
||||
func (config *Config) SetBech32PrefixForValidator(addressPrefix, pubKeyPrefix string) {
|
||||
config.assertNotSealed()
|
||||
config.bech32AddressPrefix["validator_addr"] = addressPrefix
|
||||
config.bech32AddressPrefix["validator_pub"] = pubKeyPrefix
|
||||
}
|
||||
|
||||
// SetBech32PrefixForConsensusNode builds the Config with Bech32 addressPrefix and publKeyPrefix for consensus nodes
|
||||
// and returns the config instance
|
||||
func (config *Config) SetBech32PrefixForConsensusNode(addressPrefix, pubKeyPrefix string) {
|
||||
config.assertNotSealed()
|
||||
config.bech32AddressPrefix["consensus_addr"] = addressPrefix
|
||||
config.bech32AddressPrefix["consensus_pub"] = pubKeyPrefix
|
||||
}
|
||||
|
||||
// Seal seals the config such that the config state could not be modified further
|
||||
func (config *Config) Seal() *Config {
|
||||
config.mtx.Lock()
|
||||
defer config.mtx.Unlock()
|
||||
|
||||
config.sealed = true
|
||||
return config
|
||||
}
|
||||
|
||||
// GetBech32AccountAddrPrefix returns the Bech32 prefix for account address
|
||||
func (config *Config) GetBech32AccountAddrPrefix() string {
|
||||
return config.bech32AddressPrefix["account_addr"]
|
||||
}
|
||||
|
||||
// GetBech32ValidatorAddrPrefix returns the Bech32 prefix for validator address
|
||||
func (config *Config) GetBech32ValidatorAddrPrefix() string {
|
||||
return config.bech32AddressPrefix["validator_addr"]
|
||||
}
|
||||
|
||||
// GetBech32ConsensusAddrPrefix returns the Bech32 prefix for consensus node address
|
||||
func (config *Config) GetBech32ConsensusAddrPrefix() string {
|
||||
return config.bech32AddressPrefix["consensus_addr"]
|
||||
}
|
||||
|
||||
// GetBech32AccountPubPrefix returns the Bech32 prefix for account public key
|
||||
func (config *Config) GetBech32AccountPubPrefix() string {
|
||||
return config.bech32AddressPrefix["account_pub"]
|
||||
}
|
||||
|
||||
// GetBech32ValidatorPubPrefix returns the Bech32 prefix for validator public key
|
||||
func (config *Config) GetBech32ValidatorPubPrefix() string {
|
||||
return config.bech32AddressPrefix["validator_pub"]
|
||||
}
|
||||
|
||||
// GetBech32ConsensusPubPrefix returns the Bech32 prefix for consensus node public key
|
||||
func (config *Config) GetBech32ConsensusPubPrefix() string {
|
||||
return config.bech32AddressPrefix["consensus_pub"]
|
||||
}
|
|
@ -305,11 +305,11 @@ func TestSerializationGocodecJSON(t *testing.T) {
|
|||
func TestSerializationGocodecBinary(t *testing.T) {
|
||||
d := mustNewDecFromStr(t, "0.333")
|
||||
|
||||
bz, err := cdc.MarshalBinary(d)
|
||||
bz, err := cdc.MarshalBinaryLengthPrefixed(d)
|
||||
require.NoError(t, err)
|
||||
|
||||
var d2 Dec
|
||||
err = cdc.UnmarshalBinary(bz, &d2)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(bz, &d2)
|
||||
require.NoError(t, err)
|
||||
require.True(t, d.Equal(d2), "original: %v, unmarshalled: %v", d, d2)
|
||||
}
|
||||
|
@ -323,11 +323,11 @@ type testDEmbedStruct struct {
|
|||
// TODO make work for UnmarshalJSON
|
||||
func TestEmbeddedStructSerializationGocodec(t *testing.T) {
|
||||
obj := testDEmbedStruct{"foo", 10, NewDecWithPrec(1, 3)}
|
||||
bz, err := cdc.MarshalBinary(obj)
|
||||
bz, err := cdc.MarshalBinaryLengthPrefixed(obj)
|
||||
require.Nil(t, err)
|
||||
|
||||
var obj2 testDEmbedStruct
|
||||
err = cdc.UnmarshalBinary(bz, &obj2)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(bz, &obj2)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, obj.Field1, obj2.Field1)
|
||||
|
|
|
@ -64,7 +64,11 @@ type ValidatorSet interface {
|
|||
func(index int64, validator Validator) (stop bool))
|
||||
|
||||
// iterate through bonded validators by operator address, execute func for each validator
|
||||
IterateValidatorsBonded(Context,
|
||||
IterateBondedValidatorsByPower(Context,
|
||||
func(index int64, validator Validator) (stop bool))
|
||||
|
||||
// iterate through the consensus validator set of the last block by operator address, execute func for each validator
|
||||
IterateLastValidators(Context,
|
||||
func(index int64, validator Validator) (stop bool))
|
||||
|
||||
Validator(Context, ValAddress) Validator // get a particular validator by operator address
|
||||
|
@ -111,9 +115,9 @@ type DelegationSet interface {
|
|||
|
||||
// event hooks for staking validator object
|
||||
type StakingHooks interface {
|
||||
OnValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created
|
||||
OnValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes
|
||||
OnValidatorRemoved(ctx Context, valAddr ValAddress) // Must be called when a validator is deleted
|
||||
OnValidatorCreated(ctx Context, valAddr ValAddress) // Must be called when a validator is created
|
||||
OnValidatorModified(ctx Context, valAddr ValAddress) // Must be called when a validator's state changes
|
||||
OnValidatorRemoved(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is deleted
|
||||
|
||||
OnValidatorBonded(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is bonded
|
||||
OnValidatorBeginUnbonding(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator begins unbonding
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
|
@ -127,7 +128,7 @@ type KVStore interface {
|
|||
// Has checks if a key exists. Panics on nil key.
|
||||
Has(key []byte) bool
|
||||
|
||||
// Set sets the key. Panics on nil key.
|
||||
// Set sets the key. Panics on nil key or value.
|
||||
Set(key, value []byte)
|
||||
|
||||
// Delete deletes the key. Panics on nil key.
|
||||
|
@ -176,6 +177,43 @@ func KVStoreReversePrefixIterator(kvs KVStore, prefix []byte) Iterator {
|
|||
return kvs.ReverseIterator(prefix, PrefixEndBytes(prefix))
|
||||
}
|
||||
|
||||
// Compare two KVstores, return either the first key/value pair
|
||||
// at which they differ and whether or not they are equal, skipping
|
||||
// value comparison for a set of provided prefixes
|
||||
func DiffKVStores(a KVStore, b KVStore, prefixesToSkip [][]byte) (kvA cmn.KVPair, kvB cmn.KVPair, count int64, equal bool) {
|
||||
iterA := a.Iterator(nil, nil)
|
||||
iterB := b.Iterator(nil, nil)
|
||||
count = int64(0)
|
||||
for {
|
||||
if !iterA.Valid() && !iterB.Valid() {
|
||||
break
|
||||
}
|
||||
var kvA, kvB cmn.KVPair
|
||||
if iterA.Valid() {
|
||||
kvA = cmn.KVPair{Key: iterA.Key(), Value: iterA.Value()}
|
||||
iterA.Next()
|
||||
}
|
||||
if iterB.Valid() {
|
||||
kvB = cmn.KVPair{Key: iterB.Key(), Value: iterB.Value()}
|
||||
iterB.Next()
|
||||
}
|
||||
compareValue := true
|
||||
for _, prefix := range prefixesToSkip {
|
||||
if bytes.Equal(kvA.Key[:len(prefix)], prefix) {
|
||||
compareValue = false
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(kvA.Key, kvB.Key) {
|
||||
return kvA, kvB, count, false
|
||||
}
|
||||
if compareValue && !bytes.Equal(kvA.Value, kvB.Value) {
|
||||
return kvA, kvB, count, false
|
||||
}
|
||||
count++
|
||||
}
|
||||
return cmn.KVPair{}, cmn.KVPair{}, count, true
|
||||
}
|
||||
|
||||
// CacheKVStore cache-wraps a KVStore. After calling .Write() on
|
||||
// the CacheKVStore, all previously created CacheKVStores on the
|
||||
// object expire.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
|
@ -36,6 +37,13 @@ func MustSortJSON(toSortJSON []byte) []byte {
|
|||
return js
|
||||
}
|
||||
|
||||
// Uint64ToBigEndian - marshals uint64 to a bigendian byte slice so it can be sorted
|
||||
func Uint64ToBigEndian(i uint64) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, i)
|
||||
return b
|
||||
}
|
||||
|
||||
// Slight modification of the RFC3339Nano but it right pads all zeros and drops the time zone info
|
||||
const SortableTimeFormat = "2006-01-02T15:04:05.000000000"
|
||||
|
||||
|
|
|
@ -93,16 +93,16 @@ func TestBaseAccountMarshal(t *testing.T) {
|
|||
cdc := codec.New()
|
||||
codec.RegisterCrypto(cdc)
|
||||
|
||||
b, err := cdc.MarshalBinary(acc)
|
||||
b, err := cdc.MarshalBinaryLengthPrefixed(acc)
|
||||
require.Nil(t, err)
|
||||
|
||||
acc2 := BaseAccount{}
|
||||
err = cdc.UnmarshalBinary(b, &acc2)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(b, &acc2)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, acc, acc2)
|
||||
|
||||
// error on bad bytes
|
||||
acc2 = BaseAccount{}
|
||||
err = cdc.UnmarshalBinary(b[:len(b)/2], &acc2)
|
||||
err = cdc.UnmarshalBinaryLengthPrefixed(b[:len(b)/2], &acc2)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
|
|
@ -282,7 +282,8 @@ func ensureSufficientMempoolFees(ctx sdk.Context, stdTx StdTx) sdk.Result {
|
|||
// TODO: Make the gasPrice not a constant, and account for tx size.
|
||||
requiredFees := adjustFeesByGas(ctx.MinimumFees(), stdTx.Fee.Gas)
|
||||
|
||||
if !ctx.MinimumFees().IsZero() && stdTx.Fee.Amount.IsLT(requiredFees) {
|
||||
// NOTE: !A.IsAllGTE(B) is not the same as A.IsAllLT(B).
|
||||
if !ctx.MinimumFees().IsZero() && !stdTx.Fee.Amount.IsAllGTE(requiredFees) {
|
||||
// validators reject any tx from the mempool with less than the minimum fee per gas * gas factor
|
||||
return sdk.ErrInsufficientFee(fmt.Sprintf(
|
||||
"insufficient fee, got: %q required: %q", stdTx.Fee.Amount, requiredFees)).Result()
|
||||
|
|
|
@ -2,9 +2,9 @@ package cli
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/viper"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
|
@ -13,13 +13,14 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/spf13/cobra"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
const (
|
||||
flagAppend = "append"
|
||||
flagPrintSigs = "print-sigs"
|
||||
flagOffline = "offline"
|
||||
flagAppend = "append"
|
||||
flagValidateSigs = "validate-signatures"
|
||||
flagOffline = "offline"
|
||||
flagSigOnly = "signature-only"
|
||||
)
|
||||
|
||||
// GetSignCommand returns the sign command
|
||||
|
@ -30,6 +31,13 @@ func GetSignCommand(codec *amino.Codec, decoder auth.AccountDecoder) *cobra.Comm
|
|||
Long: `Sign transactions created with the --generate-only flag.
|
||||
Read a transaction from <file>, sign it, and print its JSON encoding.
|
||||
|
||||
If the flag --signature-only flag is on, it outputs a JSON representation
|
||||
of the generated signature only.
|
||||
|
||||
If the flag --validate-signatures is on, then the command would check whether all required
|
||||
signers have signed the transactions and whether the signatures were collected in the right
|
||||
order.
|
||||
|
||||
The --offline flag makes sure that the client will not reach out to the local cache.
|
||||
Thus account number or sequence number lookups will not be performed and it is
|
||||
recommended to set such parameters manually.`,
|
||||
|
@ -37,8 +45,11 @@ recommended to set such parameters manually.`,
|
|||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
cmd.Flags().String(client.FlagName, "", "Name of private key with which to sign")
|
||||
cmd.Flags().Bool(flagAppend, true, "Append the signature to the existing ones. If disabled, old signatures would be overwritten")
|
||||
cmd.Flags().Bool(flagPrintSigs, false, "Print the addresses that must sign the transaction and those who have already signed it, then exit")
|
||||
cmd.Flags().Bool(flagAppend, true,
|
||||
"Append the signature to the existing ones. If disabled, old signatures would be overwritten")
|
||||
cmd.Flags().Bool(flagSigOnly, false, "Print only the generated signature, then exit.")
|
||||
cmd.Flags().Bool(flagValidateSigs, false, "Print the addresses that must sign the transaction, "+
|
||||
"those who have already signed it, and make sure that signatures are in the correct order.")
|
||||
cmd.Flags().Bool(flagOffline, false, "Offline mode. Do not query local cache.")
|
||||
return cmd
|
||||
}
|
||||
|
@ -50,24 +61,45 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
|
|||
return
|
||||
}
|
||||
|
||||
if viper.GetBool(flagPrintSigs) {
|
||||
printSignatures(stdTx)
|
||||
if viper.GetBool(flagValidateSigs) {
|
||||
if !printSignatures(stdTx) {
|
||||
return fmt.Errorf("signatures validation failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
name := viper.GetString(client.FlagName)
|
||||
if name == "" {
|
||||
return errors.New("required flag \"name\" has not been set")
|
||||
}
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(decoder)
|
||||
txBldr := authtxb.NewTxBuilderFromCLI()
|
||||
|
||||
newTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, viper.GetBool(flagAppend), viper.GetBool(flagOffline))
|
||||
// if --signature-only is on, then override --append
|
||||
generateSignatureOnly := viper.GetBool(flagSigOnly)
|
||||
appendSig := viper.GetBool(flagAppend) && !generateSignatureOnly
|
||||
newTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, appendSig, viper.GetBool(flagOffline))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var json []byte
|
||||
if cliCtx.Indent {
|
||||
json, err = cdc.MarshalJSONIndent(newTx, "", " ")
|
||||
} else {
|
||||
json, err = cdc.MarshalJSON(newTx)
|
||||
|
||||
switch generateSignatureOnly {
|
||||
case true:
|
||||
switch cliCtx.Indent {
|
||||
case true:
|
||||
json, err = cdc.MarshalJSONIndent(newTx.Signatures[0], "", " ")
|
||||
default:
|
||||
json, err = cdc.MarshalJSON(newTx.Signatures[0])
|
||||
}
|
||||
default:
|
||||
switch cliCtx.Indent {
|
||||
case true:
|
||||
json, err = cdc.MarshalJSONIndent(newTx, "", " ")
|
||||
default:
|
||||
json, err = cdc.MarshalJSON(newTx)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -77,17 +109,31 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
|
|||
}
|
||||
}
|
||||
|
||||
func printSignatures(stdTx auth.StdTx) {
|
||||
func printSignatures(stdTx auth.StdTx) bool {
|
||||
fmt.Println("Signers:")
|
||||
for i, signer := range stdTx.GetSigners() {
|
||||
signers := stdTx.GetSigners()
|
||||
for i, signer := range signers {
|
||||
fmt.Printf(" %v: %v\n", i, signer.String())
|
||||
}
|
||||
|
||||
sigs := stdTx.GetSignatures()
|
||||
fmt.Println("")
|
||||
fmt.Println("Signatures:")
|
||||
for i, sig := range stdTx.GetSignatures() {
|
||||
fmt.Printf(" %v: %v\n", i, sdk.AccAddress(sig.Address()).String())
|
||||
success := true
|
||||
if len(sigs) != len(signers) {
|
||||
success = false
|
||||
}
|
||||
return
|
||||
for i, sig := range stdTx.GetSignatures() {
|
||||
sigAddr := sdk.AccAddress(sig.Address())
|
||||
sigSanity := "OK"
|
||||
if i >= len(signers) || !sigAddr.Equals(signers[i]) {
|
||||
sigSanity = fmt.Sprintf("ERROR: signature %d does not match its respective signer", i)
|
||||
success = false
|
||||
}
|
||||
fmt.Printf(" %v: %v\t[%s]\n", i, sigAddr.String(), sigSanity)
|
||||
}
|
||||
fmt.Println("")
|
||||
return success
|
||||
}
|
||||
|
||||
func readAndUnmarshalStdTx(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err error) {
|
||||
|
|
|
@ -125,7 +125,8 @@ func (bldr TxBuilder) Sign(name, passphrase string, msg StdSignMsg) ([]byte, err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bldr.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, []auth.StdSignature{sig}, msg.Memo))
|
||||
|
||||
return bldr.Codec.MarshalBinaryLengthPrefixed(auth.NewStdTx(msg.Msgs, msg.Fee, []auth.StdSignature{sig}, msg.Memo))
|
||||
}
|
||||
|
||||
// BuildAndSign builds a single message to be signed, and signs a transaction
|
||||
|
@ -166,7 +167,7 @@ func (bldr TxBuilder) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, erro
|
|||
PubKey: info.GetPubKey(),
|
||||
}}
|
||||
|
||||
return bldr.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
|
||||
return bldr.Codec.MarshalBinaryLengthPrefixed(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
|
||||
}
|
||||
|
||||
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If append
|
||||
|
|
|
@ -36,12 +36,12 @@ func (fck FeeCollectionKeeper) GetCollectedFees(ctx sdk.Context) sdk.Coins {
|
|||
}
|
||||
|
||||
feePool := &(sdk.Coins{})
|
||||
fck.cdc.MustUnmarshalBinary(bz, feePool)
|
||||
fck.cdc.MustUnmarshalBinaryLengthPrefixed(bz, feePool)
|
||||
return *feePool
|
||||
}
|
||||
|
||||
func (fck FeeCollectionKeeper) setCollectedFees(ctx sdk.Context, coins sdk.Coins) {
|
||||
bz := fck.cdc.MustMarshalBinary(coins)
|
||||
bz := fck.cdc.MustMarshalBinaryLengthPrefixed(coins)
|
||||
store := ctx.KVStore(fck.key)
|
||||
store.Set(collectedFeesKey, bz)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// GenesisState - all auth state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
CollectedFees sdk.Coins `json:"collected_fees"` // collected fees
|
||||
}
|
||||
|
||||
// Create a new genesis state
|
||||
func NewGenesisState(collectedFees sdk.Coins) GenesisState {
|
||||
return GenesisState{
|
||||
CollectedFees: collectedFees,
|
||||
}
|
||||
}
|
||||
|
||||
// Return a default genesis state
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return NewGenesisState(sdk.Coins{})
|
||||
}
|
||||
|
||||
// Init store state from genesis data
|
||||
func InitGenesis(ctx sdk.Context, keeper FeeCollectionKeeper, data GenesisState) {
|
||||
keeper.setCollectedFees(ctx, data.CollectedFees)
|
||||
}
|
||||
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper
|
||||
func ExportGenesis(ctx sdk.Context, keeper FeeCollectionKeeper) GenesisState {
|
||||
collectedFees := keeper.GetCollectedFees(ctx)
|
||||
return NewGenesisState(collectedFees)
|
||||
}
|
|
@ -148,13 +148,13 @@ func (am AccountKeeper) GetNextAccountNumber(ctx sdk.Context) int64 {
|
|||
if bz == nil {
|
||||
accNumber = 0
|
||||
} else {
|
||||
err := am.cdc.UnmarshalBinary(bz, &accNumber)
|
||||
err := am.cdc.UnmarshalBinaryLengthPrefixed(bz, &accNumber)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
bz = am.cdc.MustMarshalBinary(accNumber + 1)
|
||||
bz = am.cdc.MustMarshalBinaryLengthPrefixed(accNumber + 1)
|
||||
store.Set(globalAccountNumberKey, bz)
|
||||
|
||||
return accNumber
|
|
@ -3,15 +3,13 @@ package auth
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
codec "github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
)
|
||||
|
||||
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) {
|
||||
|
@ -115,9 +113,92 @@ func BenchmarkAccountMapperGetAccountFound(b *testing.B) {
|
|||
acc := mapper.NewAccountWithAddress(ctx, addr)
|
||||
mapper.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)}
|
||||
mapper.GetAccount(ctx, sdk.AccAddress(arr))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAccountMapperGetAccountFoundWithCoins(b *testing.B) {
|
||||
ms, capKey, _ := setupMultiStore()
|
||||
cdc := codec.New()
|
||||
RegisterBaseAccount(cdc)
|
||||
|
||||
// make context and mapper
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger())
|
||||
mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount)
|
||||
|
||||
coins := sdk.Coins{
|
||||
sdk.NewCoin("LTC", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("BTC", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("ETH", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("XRP", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("BCH", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("EOS", sdk.NewInt(1000)),
|
||||
}
|
||||
|
||||
// assumes b.N < 2**24
|
||||
for i := 0; i < b.N; i++ {
|
||||
arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)}
|
||||
addr := sdk.AccAddress(arr)
|
||||
acc := mapper.NewAccountWithAddress(ctx, addr)
|
||||
acc.SetCoins(coins)
|
||||
mapper.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)}
|
||||
mapper.GetAccount(ctx, sdk.AccAddress(arr))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAccountMapperSetAccount(b *testing.B) {
|
||||
ms, capKey, _ := setupMultiStore()
|
||||
cdc := codec.New()
|
||||
RegisterBaseAccount(cdc)
|
||||
|
||||
// make context and mapper
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger())
|
||||
mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount)
|
||||
|
||||
b.ResetTimer()
|
||||
// assumes b.N < 2**24
|
||||
for i := 0; i < b.N; i++ {
|
||||
arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)}
|
||||
addr := sdk.AccAddress(arr)
|
||||
acc := mapper.NewAccountWithAddress(ctx, addr)
|
||||
mapper.SetAccount(ctx, acc)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAccountMapperSetAccountWithCoins(b *testing.B) {
|
||||
ms, capKey, _ := setupMultiStore()
|
||||
cdc := codec.New()
|
||||
RegisterBaseAccount(cdc)
|
||||
|
||||
// make context and mapper
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger())
|
||||
mapper := NewAccountKeeper(cdc, capKey, ProtoBaseAccount)
|
||||
|
||||
coins := sdk.Coins{
|
||||
sdk.NewCoin("LTC", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("BTC", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("ETH", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("XRP", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("BCH", sdk.NewInt(1000)),
|
||||
sdk.NewCoin("EOS", sdk.NewInt(1000)),
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
// assumes b.N < 2**24
|
||||
for i := 0; i < b.N; i++ {
|
||||
arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)}
|
||||
addr := sdk.AccAddress(arr)
|
||||
acc := mapper.NewAccountWithAddress(ctx, addr)
|
||||
acc.SetCoins(coins)
|
||||
mapper.SetAccount(ctx, acc)
|
||||
}
|
||||
}
|
|
@ -151,10 +151,11 @@ func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder {
|
|||
|
||||
// StdTx.Msg is an interface. The concrete types
|
||||
// are registered by MakeTxCodec
|
||||
err := cdc.UnmarshalBinary(txBytes, &tx)
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrTxDecode("").TraceSDK(err.Error())
|
||||
}
|
||||
|
||||
return tx, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ in place of an input filename, the command reads from standard input.`,
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
txBytes, err := cliCtx.Codec.MarshalBinary(stdTx)
|
||||
|
||||
txBytes, err := cliCtx.Codec.MarshalBinaryLengthPrefixed(stdTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
// ensure account has enough coins
|
||||
if !account.GetCoins().IsGTE(coins) {
|
||||
if !account.GetCoins().IsAllGTE(coins) {
|
||||
return errors.Errorf("Address %s doesn't have enough coins to pay for this transaction.", from)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,12 @@ func BroadcastTxRequestHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) ht
|
|||
return
|
||||
}
|
||||
|
||||
txBytes, err := cliCtx.Codec.MarshalBinary(m.Tx)
|
||||
txBytes, err := cliCtx.Codec.MarshalBinaryLengthPrefixed(m.Tx)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
|
|
|
@ -190,7 +190,7 @@ func setCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt s
|
|||
// HasCoins returns whether or not an account has at least amt coins.
|
||||
func hasCoins(ctx sdk.Context, am auth.AccountKeeper, addr sdk.AccAddress, amt sdk.Coins) bool {
|
||||
ctx.GasMeter().ConsumeGas(costHasCoins, "hasCoins")
|
||||
return getCoins(ctx, am, addr).IsGTE(amt)
|
||||
return getCoins(ctx, am, addr).IsAllGTE(amt)
|
||||
}
|
||||
|
||||
// SubtractCoins subtracts amt from the coins at the addr.
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
// NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances
|
||||
func NonnegativeBalanceInvariant(mapper auth.AccountKeeper) simulation.Invariant {
|
||||
return func(app *baseapp.BaseApp, _ abci.Header) error {
|
||||
return func(app *baseapp.BaseApp) error {
|
||||
ctx := app.NewContext(false, abci.Header{})
|
||||
accts := mock.GetAllAccounts(mapper, ctx)
|
||||
for _, acc := range accts {
|
||||
|
@ -32,7 +32,7 @@ func NonnegativeBalanceInvariant(mapper auth.AccountKeeper) simulation.Invariant
|
|||
// TotalCoinsInvariant checks that the sum of the coins across all accounts
|
||||
// is what is expected
|
||||
func TotalCoinsInvariant(mapper auth.AccountKeeper, totalSupplyFn func() sdk.Coins) simulation.Invariant {
|
||||
return func(app *baseapp.BaseApp, _ abci.Header) error {
|
||||
return func(app *baseapp.BaseApp) error {
|
||||
ctx := app.NewContext(false, abci.Header{})
|
||||
totalCoins := sdk.Coins{}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue