diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a4c6acf7b..f4ad1c0d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,26 @@ # Changelog +## 0.21.0 + +*TBD* + +BREAKING CHANGES +* [x/stake] Specify DelegatorAddress in MsgCreateValidator +* [x/auth] NewAccountMapper takes a constructor instead of a prototype + +FEATURES +* [baseapp] NewBaseApp now takes option functions as parameters + ## 0.20.0 -*TBD* +*July 10th, 2018* BREAKING CHANGES * msg.GetSignBytes() returns sorted JSON (by key) * msg.GetSignBytes() field changes * `msg_bytes` -> `msgs` * `fee_bytes` -> `fee` -* Update Tendermint to v0.22.0 +* Update Tendermint to v0.22.2 * Default ports changed from 466xx to 266xx * Amino JSON uses type names instead of prefix bytes * ED25519 addresses are the first 20-bytes of the SHA256 of the raw 32-byte @@ -21,7 +32,6 @@ BREAKING CHANGES * [auth] Removed MsgChangePubKey * [auth] Removed SetPubKey from account mapper * [auth] AltBytes renamed to Memo, now a string, max 100 characters, costs a bit of gas -* [baseapp] NewBaseApp now takes option functions as parameters * [types] `GetMsg()` -> `GetMsgs()` as txs wrap many messages * [types] Removed GetMemo from Tx (it is still on StdTx) * [types] renamed rational.Evaluate to rational.Round{Int64, Int} diff --git a/Gopkg.lock b/Gopkg.lock index 8794539880..a73a2009a5 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -29,13 +29,13 @@ branch = "master" name = "github.com/btcsuite/btcd" packages = ["btcec"] - revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64" + revision = "fdfc19097e7ac6b57035062056f5b7b4638b8898" [[projects]] branch = "master" name = "github.com/btcsuite/btcutil" packages = ["bech32"] - revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4" + revision = "ab6388e0c60ae4834a1f57511e20c17b5f78be4b" [[projects]] name = "github.com/davecgh/go-spew" @@ -103,8 +103,8 @@ "ptypes/duration", "ptypes/timestamp" ] - revision = "925541529c1fa6821df4e44ce2723319eb2be768" - version = "v1.0.0" + revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" + version = "v1.1.0" [[projects]] branch = "master" @@ -137,7 +137,6 @@ ".", "hcl/ast", "hcl/parser", - "hcl/printer", "hcl/scanner", "hcl/strconv", "hcl/token", @@ -208,13 +207,13 @@ version = "v1.0.0" [[projects]] + branch = "master" name = "github.com/prometheus/client_golang" packages = [ "prometheus", "prometheus/promhttp" ] - revision = "c5b7fccd204277076155f10851dad72b76a49317" - version = "v0.8.0" + revision = "ae27198cdd90bf12cd134ad79d1366a6cf49f632" [[projects]] branch = "master" @@ -314,7 +313,7 @@ "leveldb/table", "leveldb/util" ] - revision = "0d5a0ceb10cf9ab89fdd744cc8c50a83134f6697" + revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445" [[projects]] branch = "master" @@ -335,8 +334,8 @@ [[projects]] name = "github.com/tendermint/iavl" packages = ["."] - revision = "9e5dc3e61f70b285bb25414452d47aca1ff34c1d" - version = "v0.8.2-rc0" + revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9" + version = "v0.9.2" [[projects]] name = "github.com/tendermint/tendermint" @@ -395,8 +394,8 @@ "types", "version" ] - revision = "5923b6288fe8ce9581936ee97c2bf9cf9c02c2f4" - version = "v0.22.0-rc2" + revision = "5ff65274b84ea905787a48512cc3124385bddf2f" + version = "v0.22.2" [[projects]] name = "github.com/zondax/ledger-goclient" @@ -434,13 +433,13 @@ "netutil", "trace" ] - revision = "ed29d75add3d7c4bf7ca65aac0c6df3d1420216f" + revision = "292b43bbf7cb8d35ddf40f8d5100ef3837cced3f" [[projects]] branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "151529c776cdc58ddbe7963ba9af779f3577b419" + revision = "1b2967e3c290b7c545b3db0deeda16e9be4f98a2" [[projects]] name = "golang.org/x/text" @@ -464,9 +463,10 @@ version = "v0.3.0" [[projects]] + branch = "master" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] - revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" + revision = "e92b116572682a5b432ddd840aeaba2a559eeff1" [[projects]] name = "google.golang.org/grpc" @@ -507,6 +507,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "13ad2a57b6942729e2d08b5c37810d62108aa64a335a4822fcff1ad992c0662b" + inputs-digest = "37c54ed9bde68bad33be02f5e09b17a42397fb2fc9a10fa582e66b3852a99370" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 0a4d3b2f17..0bb13c3e38 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -28,9 +28,9 @@ name = "github.com/bgentry/speakeasy" version = "~0.1.0" -[[constraint]] +[[override]] name = "github.com/golang/protobuf" - version = "~1.0.0" + version = "=1.1.0" [[constraint]] name = "github.com/mattn/go-isatty" @@ -52,17 +52,17 @@ name = "github.com/stretchr/testify" version = "=1.2.1" -[[constraint]] +[[override]] name = "github.com/tendermint/go-amino" version = "=0.10.1" -[[constraint]] +[[override]] name = "github.com/tendermint/iavl" - version = "=v0.8.2-rc0" + version = "=v0.9.2" -[[constraint]] +[[override]] name = "github.com/tendermint/tendermint" - version = "=0.22.0-rc2" + version = "=0.22.2" [[constraint]] name = "github.com/bartekn/go-bip39" @@ -72,11 +72,6 @@ name = "github.com/zondax/ledger-goclient" revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a" -# this got updated and broke, so locked to an old working commit ... -[[override]] - name = "google.golang.org/genproto" - revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" - [prune] go-tests = true unused-packages = true diff --git a/README.md b/README.md index 0383fded2a..e865a2c55b 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,14 @@ ![banner](docs/graphics/cosmos-sdk-image.png) [![version](https://img.shields.io/github/tag/cosmos/cosmos-sdk.svg)](https://github.com/cosmos/cosmos-sdk/releases/latest) +[![CircleCI](https://circleci.com/gh/cosmos/cosmos-sdk/tree/master.svg?style=shield)](https://circleci.com/gh/cosmos/cosmos-sdk/tree/master) +[![codecov](https://codecov.io/gh/cosmos/cosmos-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/cosmos/cosmos-sdk) +[![Go Report Card](https://goreportcard.com/badge/github.com/cosmos/cosmos-sdk)](https://goreportcard.com/report/github.com/cosmos/cosmos-sdk) +[![license](https://img.shields.io/github/license/cosmos/cosmos-sdk.svg)](https://github.com/cosmos/cosmos-sdk/blob/master/LICENSE) +[![LoC](https://tokei.rs/b1/github/cosmos/cosmos-sdk)](https://github.com/cosmos/cosmos-sdk) [![API Reference](https://godoc.org/github.com/cosmos/cosmos-sdk?status.svg )](https://godoc.org/github.com/cosmos/cosmos-sdk) [![riot.im](https://img.shields.io/badge/riot.im-JOIN%20CHAT-green.svg)](https://riot.im/app/#/room/#cosmos-sdk:matrix.org) -[![license](https://img.shields.io/github/license/cosmos/cosmos-sdk.svg)](https://github.com/cosmos/cosmos-sdk/blob/master/LICENSE) -[![LoC](https://tokei.rs/b1/github/cosmos/cosmos-sdk)](https://github.com/cosmos/cosmos-sdk) -[![Go Report Card](https://goreportcard.com/badge/github.com/cosmos/cosmos-sdk)](https://goreportcard.com/report/github.com/cosmos/cosmos-sdk) - -Branch | Tests | Coverage -----------|-------|--------- -develop | [![CircleCI](https://circleci.com/gh/cosmos/cosmos-sdk/tree/develop.svg?style=shield)](https://circleci.com/gh/cosmos/cosmos-sdk/tree/develop) | [![codecov](https://codecov.io/gh/cosmos/cosmos-sdk/branch/develop/graph/badge.svg)](https://codecov.io/gh/cosmos/cosmos-sdk) -master | [![CircleCI](https://circleci.com/gh/cosmos/cosmos-sdk/tree/master.svg?style=shield)](https://circleci.com/gh/cosmos/cosmos-sdk/tree/master) | [![codecov](https://codecov.io/gh/cosmos/cosmos-sdk/branch/master/graph/badge.svg)](https://codecov.io/gh/cosmos/cosmos-sdk) The Cosmos-SDK is a framework for building blockchain applications in Golang. It is being used to build `Gaia`, the first implementation of the [Cosmos Hub](https://cosmos.network), @@ -20,6 +17,9 @@ It is being used to build `Gaia`, the first implementation of the [Cosmos Hub](h **WARNING**: The SDK has mostly stabilized, but we are still making some breaking changes. +**Note**: The `master` branch is an active development branch. For the latest +release, see the [release page](https://github.com/cosmos/cosmos-sdk/releases). + **Note**: Requires [Go 1.10+](https://golang.org/dl/) ## Gaia Testnet diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index b5800ca292..0979a568f6 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -729,7 +729,7 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, { "delegator_addr": "%s", "validator_addr": "%s", - "bond": { "denom": "%s", "amount": "60" } + "delegation": { "denom": "%s", "amount": "60" } } ], "begin_unbondings": [], diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 72defe3012..40e8686694 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -74,8 +74,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // define the accountMapper app.accountMapper = auth.NewAccountMapper( app.cdc, - app.keyAccount, // target store - &auth.BaseAccount{}, // prototype + app.keyAccount, // target store + auth.ProtoBaseAccount, // prototype ) // add handlers diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index b06328d134..121f437a3c 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -157,8 +157,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp { // define the accountMapper app.accountMapper = auth.NewAccountMapper( app.cdc, - app.keyAccount, // target store - &auth.BaseAccount{}, // prototype + app.keyAccount, // target store + auth.ProtoBaseAccount, // prototype ) // add handlers diff --git a/cmd/gaia/testnets/STATUS.md b/cmd/gaia/testnets/STATUS.md index 0848f27efe..00f7a58607 100644 --- a/cmd/gaia/testnets/STATUS.md +++ b/cmd/gaia/testnets/STATUS.md @@ -1,5 +1,10 @@ # TESTNET STATUS +## *July 2, 2018, 1:00 EST* - Gaia-6002 slashing failure + +- Gaia-6002 has been halted due to a slashing issue. +- The team is taking its time to look into this Gaia-7000 will be introduced this week. + ## *June 13, 2018, 17:00 EST* - Gaia-6002 is making blocks! - Gaia-6002 is live and making blocks diff --git a/docs/core/app3.md b/docs/core/app3.md index 450b1a59e0..459f48c838 100644 --- a/docs/core/app3.md +++ b/docs/core/app3.md @@ -105,7 +105,7 @@ Creating an AccountMapper is easy - we just need to specify a codec, a capability key, and a prototype of the object being encoded ```go -accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) +accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount) ``` Then we can get, modify, and set accounts. For instance, we could double the @@ -335,7 +335,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { keyFees := sdk.NewKVStoreKey("fee") // TODO // Set various mappers/keepers to interact easily with underlying stores - accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount) coinKeeper := bank.NewKeeper(accountMapper) feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) diff --git a/docs/core/examples/app3.go b/docs/core/examples/app3.go index f99e34b8b2..853ad687e1 100644 --- a/docs/core/examples/app3.go +++ b/docs/core/examples/app3.go @@ -28,7 +28,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { keyFees := sdk.NewKVStoreKey("fee") // TODO // Set various mappers/keepers to interact easily with underlying stores - accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount) coinKeeper := bank.NewKeeper(accountMapper) feeKeeper := auth.NewFeeCollectionKeeper(cdc, keyFees) diff --git a/docs/core/examples/app4.go b/docs/core/examples/app4.go index daabe1561e..a8ef37cee5 100644 --- a/docs/core/examples/app4.go +++ b/docs/core/examples/app4.go @@ -28,7 +28,7 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { keyAccount := sdk.NewKVStoreKey("acc") // Set various mappers/keepers to interact easily with underlying stores - accountMapper := auth.NewAccountMapper(cdc, keyAccount, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, keyAccount, auth.ProtoBaseAccount) coinKeeper := bank.NewKeeper(accountMapper) // TODO diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000000..31fdbfca6f --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,11 @@ +.. Cosmos-SDK documentation master file, created by + sphinx-quickstart on Fri Sep 1 21:37:02 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to the Cosmos SDK! +========================== + +This location for our documentation has been deprecated, please see: + +- https://cosmos.network/docs/ diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index 6df74ef28c..7b2c7af3a3 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -62,8 +62,8 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { // define and attach the mappers and keepers app.accountMapper = auth.NewAccountMapper( cdc, - app.keyAccount, // target store - &types.AppAccount{}, // prototype + app.keyAccount, // target store + auth.ProtoBaseAccount, // prototype ) app.coinKeeper = bank.NewKeeper(app.accountMapper) app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 6ea7d52472..51d10002a7 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -71,7 +71,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { app.accountMapper = auth.NewAccountMapper( cdc, app.capKeyAccountStore, // target store - &types.AppAccount{}, // prototype + types.ProtoAppAccount, // prototype ) // Add handlers. diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index e74b3b700b..0b6a9b8b10 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -42,8 +42,8 @@ func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso key = "pow" value = json.RawMessage(`{ - "difficulty": 1, - "count": 0 + "difficulty": "1", + "count": "0" }`) appState, err = server.InsertKeyJSON(cdc, appState, key, value) diff --git a/examples/democoin/types/account.go b/examples/democoin/types/account.go index e491912579..8eb9b0ae42 100644 --- a/examples/democoin/types/account.go +++ b/examples/democoin/types/account.go @@ -21,6 +21,11 @@ type AppAccount struct { Name string `json:"name"` } +// Constructor for AppAccount +func ProtoAppAccount() auth.Account { + return &AppAccount{} +} + // nolint func (acc AppAccount) GetName() string { return acc.Name } func (acc *AppAccount) SetName(name string) { acc.Name = name } diff --git a/examples/democoin/x/cool/keeper_test.go b/examples/democoin/x/cool/keeper_test.go index f0d65a545e..ab59ea6101 100644 --- a/examples/democoin/x/cool/keeper_test.go +++ b/examples/democoin/x/cool/keeper_test.go @@ -29,7 +29,7 @@ func TestCoolKeeper(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) + am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount) ctx := sdk.NewContext(ms, abci.Header{}, false, nil) ck := bank.NewKeeper(am) keeper := NewKeeper(capKey, ck, DefaultCodespace) diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index 863a0dc6cc..a203d27764 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -19,7 +19,7 @@ func TestPowHandler(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) + am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) config := NewConfig("pow", int64(1)) ck := bank.NewKeeper(am) diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index 7a9b869849..a6802cb212 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -32,7 +32,7 @@ func TestPowKeeperGetSet(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - am := auth.NewAccountMapper(cdc, capKey, &auth.BaseAccount{}) + am := auth.NewAccountMapper(cdc, capKey, auth.ProtoBaseAccount) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) config := NewConfig("pow", int64(1)) ck := bank.NewKeeper(am) diff --git a/examples/democoin/x/simplestake/keeper_test.go b/examples/democoin/x/simplestake/keeper_test.go index 35910b921c..026f343465 100644 --- a/examples/democoin/x/simplestake/keeper_test.go +++ b/examples/democoin/x/simplestake/keeper_test.go @@ -35,7 +35,7 @@ func TestKeeperGetSet(t *testing.T) { cdc := wire.NewCodec() auth.RegisterBaseAccount(cdc) - accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) stakeKeeper := NewKeeper(capKey, bank.NewKeeper(accountMapper), DefaultCodespace) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) addr := sdk.AccAddress([]byte("some-address")) @@ -65,7 +65,7 @@ func TestBonding(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) coinKeeper := bank.NewKeeper(accountMapper) stakeKeeper := NewKeeper(capKey, coinKeeper, DefaultCodespace) addr := sdk.AccAddress([]byte("some-address")) diff --git a/version/version.go b/version/version.go index 4966455689..b9de4f9916 100644 --- a/version/version.go +++ b/version/version.go @@ -5,7 +5,7 @@ const Maj = "0" const Min = "20" const Fix = "0" -const Version = "0.20.0-dev" +const Version = "0.20.0" // GitCommit set by build flags var GitCommit = "" diff --git a/x/auth/account.go b/x/auth/account.go index 0e9e3075cf..3340c8bd58 100644 --- a/x/auth/account.go +++ b/x/auth/account.go @@ -46,6 +46,11 @@ type BaseAccount struct { Sequence int64 `json:"sequence"` } +// Prototype function for BaseAccount +func ProtoBaseAccount() Account { + return &BaseAccount{} +} + func NewBaseAccountWithAddress(addr sdk.AccAddress) BaseAccount { return BaseAccount{ Address: addr, diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index 8147edb2cd..c30013d32f 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -112,7 +112,7 @@ func TestAnteHandlerSigErrors(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -165,7 +165,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -224,7 +224,7 @@ func TestAnteHandlerSequences(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -302,7 +302,7 @@ func TestAnteHandlerFees(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -344,7 +344,7 @@ func TestAnteHandlerMemoGas(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -387,7 +387,7 @@ func TestAnteHandlerMultiSigner(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -438,7 +438,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) @@ -519,7 +519,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) { ms, capKey, capKey2 := setupMultiStore() cdc := wire.NewCodec() RegisterBaseAccount(cdc) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) feeCollector := NewFeeCollectionKeeper(cdc, capKey2) anteHandler := NewAnteHandler(mapper, feeCollector) ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger()) diff --git a/x/auth/mapper.go b/x/auth/mapper.go index 88cedcb154..244527af3f 100644 --- a/x/auth/mapper.go +++ b/x/auth/mapper.go @@ -1,9 +1,6 @@ package auth import ( - "fmt" - "reflect" - sdk "github.com/cosmos/cosmos-sdk/types" wire "github.com/cosmos/cosmos-sdk/wire" "github.com/tendermint/tendermint/crypto" @@ -18,8 +15,8 @@ type AccountMapper struct { // The (unexposed) key used to access the store from the Context. key sdk.StoreKey - // The prototypical Account concrete type. - proto Account + // The prototypical Account constructor. + proto func() Account // The wire codec for binary encoding/decoding of accounts. cdc *wire.Codec @@ -28,7 +25,7 @@ type AccountMapper struct { // NewAccountMapper returns a new sdk.AccountMapper that // uses go-amino to (binary) encode and decode concrete sdk.Accounts. // nolint -func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto Account) AccountMapper { +func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto func() Account) AccountMapper { return AccountMapper{ key: key, proto: proto, @@ -38,7 +35,7 @@ func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto Account) AccountM // Implaements sdk.AccountMapper. func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) Account { - acc := am.clonePrototype() + acc := am.proto() err := acc.SetAddress(addr) if err != nil { // Handle w/ #870 @@ -158,30 +155,6 @@ func (am AccountMapper) GetNextAccountNumber(ctx sdk.Context) int64 { //---------------------------------------- // misc. -// Creates a new struct (or pointer to struct) from am.proto. -func (am AccountMapper) clonePrototype() Account { - protoRt := reflect.TypeOf(am.proto) - if protoRt.Kind() == reflect.Ptr { - protoCrt := protoRt.Elem() - if protoCrt.Kind() != reflect.Struct { - panic("accountMapper requires a struct proto sdk.Account, or a pointer to one") - } - protoRv := reflect.New(protoCrt) - clone, ok := protoRv.Interface().(Account) - if !ok { - panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt)) - } - return clone - } - - protoRv := reflect.New(protoRt).Elem() - clone, ok := protoRv.Interface().(Account) - if !ok { - panic(fmt.Sprintf("accountMapper requires a proto sdk.Account, but %v doesn't implement sdk.Account", protoRt)) - } - return clone -} - func (am AccountMapper) encodeAccount(acc Account) []byte { bz, err := am.cdc.MarshalBinaryBare(acc) if err != nil { diff --git a/x/auth/mapper_test.go b/x/auth/mapper_test.go index e7271a2ae6..679ee12cdc 100644 --- a/x/auth/mapper_test.go +++ b/x/auth/mapper_test.go @@ -32,7 +32,7 @@ func TestAccountMapperGetSet(t *testing.T) { // make context and mapper ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - mapper := NewAccountMapper(cdc, capKey, &BaseAccount{}) + mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount) addr := sdk.AccAddress([]byte("some-address")) diff --git a/x/bank/keeper_test.go b/x/bank/keeper_test.go index 7b27d45faa..c9d7c41196 100644 --- a/x/bank/keeper_test.go +++ b/x/bank/keeper_test.go @@ -33,7 +33,7 @@ func TestKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) coinKeeper := NewKeeper(accountMapper) addr := sdk.AccAddress([]byte("addr1")) @@ -118,7 +118,7 @@ func TestSendKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) coinKeeper := NewKeeper(accountMapper) sendKeeper := NewSendKeeper(accountMapper) @@ -187,7 +187,7 @@ func TestViewKeeper(t *testing.T) { auth.RegisterBaseAccount(cdc) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewNopLogger()) - accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, authKey, auth.ProtoBaseAccount) coinKeeper := NewKeeper(accountMapper) viewKeeper := NewViewKeeper(accountMapper) diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index 8c91921bd3..06e2bd167a 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -64,7 +64,7 @@ func TestIBC(t *testing.T) { key := sdk.NewKVStoreKey("ibc") ctx := defaultContext(key) - am := auth.NewAccountMapper(cdc, key, &auth.BaseAccount{}) + am := auth.NewAccountMapper(cdc, key, auth.ProtoBaseAccount) ck := bank.NewKeeper(am) src := newAddress() diff --git a/x/mock/app.go b/x/mock/app.go index 6843d4f296..175222fa88 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -58,7 +58,7 @@ func NewApp() *App { app.AccountMapper = auth.NewAccountMapper( app.Cdc, app.KeyAccount, - &auth.BaseAccount{}, + auth.ProtoBaseAccount, ) // Initialize the app. The chainers and blockers can be overwritten before diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index b9a91f4d5b..823a6b96b6 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -59,7 +59,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep require.Nil(t, err) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout)) cdc := createTestCodec() - accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{}) + accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount) ck := bank.NewKeeper(accountMapper) sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) genesis := stake.DefaultGenesisState() @@ -94,9 +94,10 @@ func testAddr(addr string) sdk.AccAddress { func newTestMsgCreateValidator(address sdk.AccAddress, pubKey crypto.PubKey, amt sdk.Int) stake.MsgCreateValidator { return stake.MsgCreateValidator{ - Description: stake.Description{}, - ValidatorAddr: address, - PubKey: pubKey, - SelfDelegation: sdk.Coin{"steak", amt}, + Description: stake.Description{}, + DelegatorAddr: address, + ValidatorAddr: address, + PubKey: pubKey, + Delegation: sdk.Coin{"steak", amt}, } } diff --git a/x/stake/app_test.go b/x/stake/app_test.go index d1224230da..d73ef9f01f 100644 --- a/x/stake/app_test.go +++ b/x/stake/app_test.go @@ -80,7 +80,7 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, addr sdk.AccAddress, expFound bool) Validator { ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) - validator, found := keeper.GetValidator(ctxCheck, addr1) + validator, found := keeper.GetValidator(ctxCheck, addr) require.Equal(t, expFound, found) return validator @@ -138,6 +138,18 @@ func TestStakeMsgs(t *testing.T) { require.Equal(t, sdk.Bonded, validator.Status()) require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) + // addr1 create validator on behalf of addr2 + createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description) + + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, priv1, priv2) + mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)}) + mApp.BeginBlock(abci.RequestBeginBlock{}) + + validator = checkValidator(t, mApp, keeper, addr2, true) + require.Equal(t, addr2, validator.Owner) + require.Equal(t, sdk.Bonded, validator.Status()) + require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) + // check the bond that should have been created as well checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10)) @@ -145,7 +157,7 @@ func TestStakeMsgs(t *testing.T) { description = NewDescription("bar_moniker", "", "", "") editValidatorMsg := NewMsgEditValidator(addr1, description) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{1}, true, priv1) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, priv1) validator = checkValidator(t, mApp, keeper, addr1, true) require.Equal(t, description, validator.Description) @@ -153,13 +165,13 @@ func TestStakeMsgs(t *testing.T) { mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin}) delegateMsg := NewMsgDelegate(addr2, addr1, bondCoin) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{0}, true, priv2) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewRat(10)) // begin unbonding beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10)) - mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{1}, true, priv2) + mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2) // delegation should exist anymore checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Rat{}) diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index e4c4a9dcb1..72317c82c9 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -50,7 +50,17 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { Website: viper.GetString(FlagWebsite), Details: viper.GetString(FlagDetails), } - msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) + + var msg sdk.Msg + if viper.GetString(FlagAddressDelegator) != "" { + delegatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator)) + if err != nil { + return err + } + msg = stake.NewMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, amount, description) + } else { + msg = stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) + } // build and sign the transaction, then broadcast to Tendermint err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) @@ -65,6 +75,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command { cmd.Flags().AddFlagSet(fsAmount) cmd.Flags().AddFlagSet(fsDescription) cmd.Flags().AddFlagSet(fsValidator) + cmd.Flags().AddFlagSet(fsDelegator) return cmd } diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index b53b43aa57..a0f0416549 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -27,7 +27,7 @@ func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, k type msgDelegationsInput struct { DelegatorAddr string `json:"delegator_addr"` // in bech32 ValidatorAddr string `json:"validator_addr"` // in bech32 - Bond sdk.Coin `json:"bond"` + Delegation sdk.Coin `json:"delegation"` } type msgBeginRedelegateInput struct { DelegatorAddr string `json:"delegator_addr"` // in bech32 @@ -119,7 +119,7 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte messages[i] = stake.MsgDelegate{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, - Bond: msg.Bond, + Delegation: msg.Delegation, } i++ } diff --git a/x/stake/handler.go b/x/stake/handler.go index 265bb4e913..c355179cf2 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -71,7 +71,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k if found { return ErrValidatorPubKeyExists(k.Codespace()).Result() } - if msg.SelfDelegation.Denom != k.GetParams(ctx).BondDenom { + if msg.Delegation.Denom != k.GetParams(ctx).BondDenom { return ErrBadDenom(k.Codespace()).Result() } @@ -81,7 +81,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k // move coins from the msg.Address account to a (self-delegation) delegator account // the validator account and global shares are updated within here - _, err := k.Delegate(ctx, msg.ValidatorAddr, msg.SelfDelegation, validator) + _, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Delegation, validator) if err != nil { return err.Result() } @@ -130,13 +130,13 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) if !found { return ErrNoValidatorFound(k.Codespace()).Result() } - if msg.Bond.Denom != k.GetParams(ctx).BondDenom { + if msg.Delegation.Denom != k.GetParams(ctx).BondDenom { return ErrBadDenom(k.Codespace()).Result() } if validator.Revoked == true { return ErrValidatorRevoked(k.Codespace()).Result() } - _, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Bond, validator) + _, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Delegation, validator) if err != nil { return err.Result() } diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index ec0ef35f55..95a0788022 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -16,19 +16,24 @@ import ( //______________________________________________________________________ func newTestMsgCreateValidator(address sdk.AccAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator { - return MsgCreateValidator{ - Description: Description{}, - ValidatorAddr: address, - PubKey: pubKey, - SelfDelegation: sdk.Coin{"steak", sdk.NewInt(amt)}, - } + return types.NewMsgCreateValidator(address, pubKey, sdk.Coin{"steak", sdk.NewInt(amt)}, Description{}) } func newTestMsgDelegate(delegatorAddr, validatorAddr sdk.AccAddress, amt int64) MsgDelegate { return MsgDelegate{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, - Bond: sdk.Coin{"steak", sdk.NewInt(amt)}, + Delegation: sdk.Coin{"steak", sdk.NewInt(amt)}, + } +} + +func newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr sdk.AccAddress, valPubKey crypto.PubKey, amt int64) MsgCreateValidator { + return MsgCreateValidator{ + Description: Description{}, + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + PubKey: valPubKey, + Delegation: sdk.Coin{"steak", sdk.NewInt(amt)}, } } @@ -160,6 +165,32 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { assert.Equal(t, Description{}, validator.Description) } +func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) { + ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + + validatorAddr := keep.Addrs[0] + delegatorAddr := keep.Addrs[1] + pk := keep.PKs[0] + msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, 10) + got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) + require.True(t, got.IsOK(), "%v", got) + validator, found := keeper.GetValidator(ctx, validatorAddr) + + require.True(t, found) + require.Equal(t, sdk.Bonded, validator.Status()) + require.Equal(t, validatorAddr, validator.Owner) + require.Equal(t, pk, validator.PubKey) + require.Equal(t, sdk.NewRat(10), validator.PoolShares.Bonded()) + require.Equal(t, sdk.NewRat(10), validator.DelegatorShares) + require.Equal(t, Description{}, validator.Description) + + // one validator cannot be created twice even from different delegator + msgCreateValidatorOnBehalfOf.DelegatorAddr = keep.Addrs[2] + msgCreateValidatorOnBehalfOf.PubKey = keep.PKs[1] + got = handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) + require.False(t, got.IsOK(), "%v", got) +} + func TestIncrementsMsgDelegate(t *testing.T) { initBond := int64(1000) ctx, accMapper, keeper := keep.CreateTestInput(t, false, initBond) @@ -329,11 +360,12 @@ func TestMultipleMsgCreateValidator(t *testing.T) { params := setInstantUnbondPeriod(keeper, ctx) validatorAddrs := []sdk.AccAddress{keep.Addrs[0], keep.Addrs[1], keep.Addrs[2]} + delegatorAddrs := []sdk.AccAddress{keep.Addrs[3], keep.Addrs[4], keep.Addrs[5]} // bond them all for i, validatorAddr := range validatorAddrs { - msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[i], 10) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddrs[i], validatorAddr, keep.PKs[i], 10) + got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) //Check that the account is bonded @@ -341,18 +373,18 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.Equal(t, (i + 1), len(validators)) val := validators[i] balanceExpd := sdk.NewInt(initBond - 10) - balanceGot := accMapper.GetAccount(ctx, val.Owner).GetCoins().AmountOf(params.BondDenom) + balanceGot := accMapper.GetAccount(ctx, delegatorAddrs[i]).GetCoins().AmountOf(params.BondDenom) require.Equal(t, i+1, len(validators), "expected %d validators got %d, validators: %v", i+1, len(validators), validators) require.Equal(t, 10, int(val.DelegatorShares.RoundInt64()), "expected %d shares, got %d", 10, val.DelegatorShares) require.Equal(t, balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) } - // unbond them all + // unbond them all by revoking delegation for i, validatorAddr := range validatorAddrs { - validatorPre, found := keeper.GetValidator(ctx, validatorAddr) + _, found := keeper.GetValidator(ctx, validatorAddr) require.True(t, found) - msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewRat(10)) // self-delegation - msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr) + msgBeginUnbonding := NewMsgBeginUnbonding(delegatorAddrs[i], validatorAddr, sdk.NewRat(10)) // remove delegation + msgCompleteUnbonding := NewMsgCompleteUnbonding(delegatorAddrs[i], validatorAddr) got := handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper) @@ -367,7 +399,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { require.False(t, found) expBalance := sdk.NewInt(initBond) - gotBalance := accMapper.GetAccount(ctx, validatorPre.Owner).GetCoins().AmountOf(params.BondDenom) + gotBalance := accMapper.GetAccount(ctx, delegatorAddrs[i]).GetCoins().AmountOf(params.BondDenom) require.Equal(t, expBalance, gotBalance, "expected account to have %d, got %d", expBalance, gotBalance) } } diff --git a/x/stake/keeper/test_common.go b/x/stake/keeper/test_common.go index 983933123f..21073a1ff4 100644 --- a/x/stake/keeper/test_common.go +++ b/x/stake/keeper/test_common.go @@ -101,9 +101,9 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) cdc := MakeTestCodec() accountMapper := auth.NewAccountMapper( - cdc, // amino codec - keyAcc, // target store - &auth.BaseAccount{}, // prototype + cdc, // amino codec + keyAcc, // target store + auth.ProtoBaseAccount, // prototype ) ck := bank.NewKeeper(accountMapper) keeper := NewKeeper(cdc, keyStake, ck, types.DefaultCodespace) diff --git a/x/stake/stake.go b/x/stake/stake.go index c582fb6357..410856489b 100644 --- a/x/stake/stake.go +++ b/x/stake/stake.go @@ -71,13 +71,14 @@ var ( DefaultGenesisState = types.DefaultGenesisState RegisterWire = types.RegisterWire - NewMsgCreateValidator = types.NewMsgCreateValidator - NewMsgEditValidator = types.NewMsgEditValidator - NewMsgDelegate = types.NewMsgDelegate - NewMsgBeginUnbonding = types.NewMsgBeginUnbonding - NewMsgCompleteUnbonding = types.NewMsgCompleteUnbonding - NewMsgBeginRedelegate = types.NewMsgBeginRedelegate - NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate + NewMsgCreateValidator = types.NewMsgCreateValidator + NewMsgCreateValidatorOnBehalfOf = types.NewMsgCreateValidatorOnBehalfOf + NewMsgEditValidator = types.NewMsgEditValidator + NewMsgDelegate = types.NewMsgDelegate + NewMsgBeginUnbonding = types.NewMsgBeginUnbonding + NewMsgCompleteUnbonding = types.NewMsgCompleteUnbonding + NewMsgBeginRedelegate = types.NewMsgBeginRedelegate + NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate ) const ( diff --git a/x/stake/types/msg.go b/x/stake/types/msg.go index 5c00002fcb..08fd80128c 100644 --- a/x/stake/types/msg.go +++ b/x/stake/types/msg.go @@ -2,6 +2,7 @@ package types import ( "math" + "reflect" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" @@ -27,38 +28,63 @@ var maximumBondingRationalDenominator sdk.Int = sdk.NewInt(int64(math.Pow10(MaxB // MsgCreateValidator - struct for unbonding transactions type MsgCreateValidator struct { Description - ValidatorAddr sdk.AccAddress `json:"address"` - PubKey crypto.PubKey `json:"pubkey"` - SelfDelegation sdk.Coin `json:"self_delegation"` + DelegatorAddr sdk.AccAddress `json:"delegator_address"` + ValidatorAddr sdk.AccAddress `json:"validator_address"` + PubKey crypto.PubKey `json:"pubkey"` + Delegation sdk.Coin `json:"delegation"` } +// Default way to create validator. Delegator address and validator address are the same func NewMsgCreateValidator(validatorAddr sdk.AccAddress, pubkey crypto.PubKey, selfDelegation sdk.Coin, description Description) MsgCreateValidator { return MsgCreateValidator{ - Description: description, - ValidatorAddr: validatorAddr, - PubKey: pubkey, - SelfDelegation: selfDelegation, + Description: description, + DelegatorAddr: validatorAddr, + ValidatorAddr: validatorAddr, + PubKey: pubkey, + Delegation: selfDelegation, + } +} + +// Creates validator msg by delegator address on behalf of validator address +func NewMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr sdk.AccAddress, pubkey crypto.PubKey, + delegation sdk.Coin, description Description) MsgCreateValidator { + return MsgCreateValidator{ + Description: description, + DelegatorAddr: delegatorAddr, + ValidatorAddr: validatorAddr, + PubKey: pubkey, + Delegation: delegation, } } //nolint func (msg MsgCreateValidator) Type() string { return MsgType } + +// Return address(es) that must sign over msg.GetSignBytes() func (msg MsgCreateValidator) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.ValidatorAddr} + // delegator is first signer so delegator pays fees + addrs := []sdk.AccAddress{msg.DelegatorAddr} + if !reflect.DeepEqual(msg.DelegatorAddr, msg.ValidatorAddr) { + // if validator addr is not same as delegator addr, validator must sign msg as well + addrs = append(addrs, msg.ValidatorAddr) + } + return addrs } // get the bytes for the message signer to sign on func (msg MsgCreateValidator) GetSignBytes() []byte { b, err := MsgCdc.MarshalJSON(struct { Description - ValidatorAddr sdk.AccAddress `json:"address"` + DelegatorAddr sdk.AccAddress `json:"delegator_address"` + ValidatorAddr sdk.AccAddress `json:"validator_address"` PubKey string `json:"pubkey"` - Bond sdk.Coin `json:"bond"` + Delegation sdk.Coin `json:"delegation"` }{ Description: msg.Description, ValidatorAddr: msg.ValidatorAddr, PubKey: sdk.MustBech32ifyValPub(msg.PubKey), + Delegation: msg.Delegation, }) if err != nil { panic(err) @@ -68,10 +94,13 @@ func (msg MsgCreateValidator) GetSignBytes() []byte { // quick validity check func (msg MsgCreateValidator) ValidateBasic() sdk.Error { + if msg.DelegatorAddr == nil { + return ErrNilDelegatorAddr(DefaultCodespace) + } if msg.ValidatorAddr == nil { return ErrNilValidatorAddr(DefaultCodespace) } - if !(msg.SelfDelegation.Amount.GT(sdk.ZeroInt())) { + if !(msg.Delegation.Amount.GT(sdk.ZeroInt())) { return ErrBadDelegationAmount(DefaultCodespace) } empty := Description{} @@ -135,14 +164,14 @@ func (msg MsgEditValidator) ValidateBasic() sdk.Error { type MsgDelegate struct { DelegatorAddr sdk.AccAddress `json:"delegator_addr"` ValidatorAddr sdk.AccAddress `json:"validator_addr"` - Bond sdk.Coin `json:"bond"` + Delegation sdk.Coin `json:"delegation"` } -func NewMsgDelegate(delegatorAddr, validatorAddr sdk.AccAddress, bond sdk.Coin) MsgDelegate { +func NewMsgDelegate(delegatorAddr, validatorAddr sdk.AccAddress, delegation sdk.Coin) MsgDelegate { return MsgDelegate{ DelegatorAddr: delegatorAddr, ValidatorAddr: validatorAddr, - Bond: bond, + Delegation: delegation, } } @@ -169,7 +198,7 @@ func (msg MsgDelegate) ValidateBasic() sdk.Error { if msg.ValidatorAddr == nil { return ErrNilValidatorAddr(DefaultCodespace) } - if !(msg.Bond.Amount.GT(sdk.ZeroInt())) { + if !(msg.Delegation.Amount.GT(sdk.ZeroInt())) { return ErrBadDelegationAmount(DefaultCodespace) } return nil diff --git a/x/stake/types/msg_test.go b/x/stake/types/msg_test.go index d4a971bab9..73eef084a2 100644 --- a/x/stake/types/msg_test.go +++ b/x/stake/types/msg_test.go @@ -69,6 +69,46 @@ func TestMsgEditValidator(t *testing.T) { } } +// test ValidateBasic and GetSigners for MsgCreateValidatorOnBehalfOf +func TestMsgCreateValidatorOnBehalfOf(t *testing.T) { + tests := []struct { + name, moniker, identity, website, details string + delegatorAddr sdk.AccAddress + validatorAddr sdk.AccAddress + validatorPubKey crypto.PubKey + bond sdk.Coin + expectPass bool + }{ + {"basic good", "a", "b", "c", "d", addr1, addr2, pk2, coinPos, true}, + {"partial description", "", "", "c", "", addr1, addr2, pk2, coinPos, true}, + {"empty description", "", "", "", "", addr1, addr2, pk2, coinPos, false}, + {"empty delegator address", "a", "b", "c", "d", emptyAddr, addr2, pk2, coinPos, false}, + {"empty validator address", "a", "b", "c", "d", addr1, emptyAddr, pk2, coinPos, false}, + {"empty pubkey", "a", "b", "c", "d", addr1, addr2, emptyPubkey, coinPos, true}, + {"empty bond", "a", "b", "c", "d", addr1, addr2, pk2, coinZero, false}, + {"negative bond", "a", "b", "c", "d", addr1, addr2, pk2, coinNeg, false}, + {"negative bond", "a", "b", "c", "d", addr1, addr2, pk2, coinNeg, false}, + } + + for _, tc := range tests { + description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details) + msg := NewMsgCreateValidatorOnBehalfOf(tc.delegatorAddr, tc.validatorAddr, tc.validatorPubKey, tc.bond, description) + if tc.expectPass { + require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name) + } else { + require.NotNil(t, msg.ValidateBasic(), "test: %v", tc.name) + } + } + + msg := NewMsgCreateValidator(addr1, pk1, coinPos, Description{}) + addrs := msg.GetSigners() + require.Equal(t, []sdk.AccAddress{addr1}, addrs, "Signers on default msg is wrong") + + msg = NewMsgCreateValidatorOnBehalfOf(addr2, addr1, pk1, coinPos, Description{}) + addrs = msg.GetSigners() + require.Equal(t, []sdk.AccAddress{addr2, addr1}, addrs, "Signers for onbehalfof msg is wrong") +} + // test ValidateBasic for MsgDelegate func TestMsgDelegate(t *testing.T) { tests := []struct {