diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a85e301ae..6feff39e7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,13 +4,14 @@ v Before smashing the submit button please review the checkboxes. v If a checkbox is n/a - please still include it but + a little note why ☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > --> -* [ ] Updated all relevant documentation (`docs/`) -* [ ] Updated all relevant code comments -* [ ] Wrote tests -* [ ] Updated `CHANGELOG.md` -* [ ] Updated `cmd/gaia` and `examples/` +- [ ] Linked to github-issue with discussion and accepted design +- [ ] Updated all relevant documentation (`docs/`) +- [ ] Updated all relevant code comments +- [ ] Wrote tests +- [ ] Added entries in `PENDING.md` +- [ ] Updated `cmd/gaia` and `examples/` ___________________________________ For Admin Use: -* [ ] Added appropriate labels to PR (ex. wip, ready-for-review, docs) -* [ ] Reviewers Assigned -* [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)) +- [ ] Added appropriate labels to PR (ex. wip, ready-for-review, docs) +- [ ] Reviewers Assigned +- [ ] Squashed all commits, uses message "Merge pull request #XYZ: [title]" ([coding standards](https://github.com/tendermint/coding/blob/master/README.md#merging-a-pr)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index de349501c..7b7ad81fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,18 +1,52 @@ # Contributing -Thank you for considering making contributions to Cosmos-SDK and related repositories! Start by taking a look at this [coding repo](https://github.com/tendermint/coding) for overall information on repository workflow and standards. Note, we use `make get_dev_tools` and `make update_dev_tools` for installing the linting tools. +Thank you for considering making contributions to Cosmos-SDK and related +repositories! -Please follow standard github best practices: fork the repo, branch from the tip of develop, make some commits, and submit a pull request to develop. See the [open issues](https://github.com/cosmos/cosmos-sdk/issues) for things we need help with! +Contributing to this repo can mean many things such as participated in +discussion or proposing code changes. To ensure a smooth workflow for all +contributors, the general procedure for contributing has been established: -Please make sure to use `gofmt` before every commit - the easiest way to do this is have your editor run it for you upon saving a file. Additionally please ensure that your code is lint compliant by running `make lint` + 1. either [open](https://github.com/cosmos/cosmos-sdk/issues/new/choose) or + [find](https://github.com/cosmos/cosmos-sdk/issues) an issue you'd like to help with, + 2. participate in thoughtful discussion on that issue, + 3. if you would then like to contribute code: + 1. if a the issue is a proposal, ensure that the proposal has been accepted, + 2. ensure that nobody else has already begun working on this issue, if they have + make sure to contact them to collaborate, + 3. if nobody has been assigned the issue and you would like to work on it + make a comment on the issue to inform the community of your intentions + to begin work, + 4. follow standard github best practices: fork the repo, branch from the + tip of `develop`, make some commits, and submit a PR to `develop`, + 5. include `WIP:` in the PR-title to and submit your PR early, even if it's + incomplete, this indicates to the community you're working on something and + allows them to provide comments early in the development process. When the code + is complete it can be marked as ready-for-review by replacing `WIP:` with + `R4R:` in the PR-title. -Looking for a good place to start contributing? How about checking out some [good first issues](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) +Note that for very small or blatantly obvious problems (such as typos) it is +not required to an open issue to submit a PR, but be aware that for more complex +problems/features, if a PR is opened before an adequate design discussion has +taken place in a github issue, that PR runs a high likelihood of being rejected. + +Take a peek at our [coding repo](https://github.com/tendermint/coding) for +overall information on repository workflow and standards. Note, we use `make +get_dev_tools` and `make update_dev_tools` for installing the linting tools. + +Other notes: + - Looking for a good place to start contributing? How about checking out some + [good first + issues](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) + - Please make sure to use `gofmt` before every commit - the easiest way to do + this is have your editor run it for you upon saving a file. Additionally + please ensure that your code is lint compliant by running `make lint` ## Pull Requests -To accommodate review process we suggest that PRs are catagorically broken up. +To accommodate review process we suggest that PRs are categorically broken up. Ideally each PR addresses only a single issue. Additionally, as much as possible -code refactoring and cleanup should be submitted as a seperate PRs from bugfixes/feature-additions. +code refactoring and cleanup should be submitted as a separate PRs from bugfixes/feature-additions. ## Forking @@ -24,10 +58,10 @@ Instead, we use `git remote` to add the fork as a new remote for the original re For instance, to create a fork and work on a branch of it, I would: - * Create the fork on github, using the fork button. - * Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/cosmos/cosmos-sdk`) - * `git remote rename origin upstream` - * `git remote add origin git@github.com:ebuchman/basecoin.git` + - Create the fork on github, using the fork button. + - Go to the original repo checked out locally (i.e. `$GOPATH/src/github.com/cosmos/cosmos-sdk`) + - `git remote rename origin upstream` + - `git remote add origin git@github.com:ebuchman/basecoin.git` Now `origin` refers to my fork and `upstream` refers to the Cosmos-SDK version. So I can `git push -u origin master` to update my fork, and make pull requests to Cosmos-SDK from there. @@ -35,8 +69,8 @@ Of course, replace `ebuchman` with your git handle. To pull in updates from the origin repo, run - * `git fetch upstream` - * `git rebase upstream/master` (or whatever branch you want) + - `git fetch upstream` + - `git rebase upstream/master` (or whatever branch you want) Please don't make Pull Requests to `master`. @@ -100,35 +134,35 @@ Libraries need not follow the model strictly, but would be wise to. The SDK utilizes [semantic versioning](https://semver.org/). ### Development Procedure: -- the latest state of development is on `develop` -- `develop` must never fail `make test` or `make test_cli` -- `develop` should not fail `make test_lint` -- no --force onto `develop` (except when reverting a broken commit, which should seldom happen) -- create a development branch either on github.com/cosmos/cosmos-sdk, or your fork (using `git remote add origin`) -- before submitting a pull request, begin `git rebase` on top of `develop` + - the latest state of development is on `develop` + - `develop` must never fail `make test` or `make test_cli` + - `develop` should not fail `make test_lint` + - no --force onto `develop` (except when reverting a broken commit, which should seldom happen) + - create a development branch either on github.com/cosmos/cosmos-sdk, or your fork (using `git remote add origin`) + - before submitting a pull request, begin `git rebase` on top of `develop` ### Pull Merge Procedure: -- ensure pull branch is rebased on develop -- run `make test` and `make test_cli` to ensure that all tests pass -- merge pull request -- push master may request that pull requests be rebased on top of `unstable` + - ensure pull branch is rebased on develop + - run `make test` and `make test_cli` to ensure that all tests pass + - merge pull request + - push master may request that pull requests be rebased on top of `unstable` ### Release Procedure: -- start on `develop` -- prepare changelog/release issue -- bump versions -- push to release-vX.X.X to run CI -- merge to master -- merge master back to develop + - start on `develop` + - prepare changelog/release issue + - bump versions + - push to release-vX.X.X to run CI + - merge to master + - merge master back to develop ### Hotfix Procedure: -- start on `master` -- checkout a new branch named hotfix-vX.X.X -- make the required changes - - these changes should be small and an absolute necessity - - add a note to CHANGELOG.md -- bump versions -- push to hotfix-vX.X.X to run the extended integration tests on the CI -- merge hotfix-vX.X.X to master -- merge hotfix-vX.X.X to develop -- delete the hotfix-vX.X.X branch + - start on `master` + - checkout a new branch named hotfix-vX.X.X + - make the required changes + - these changes should be small and an absolute necessity + - add a note to CHANGELOG.md + - bump versions + - push to hotfix-vX.X.X to run the extended integration tests on the CI + - merge hotfix-vX.X.X to master + - merge hotfix-vX.X.X to develop + - delete the hotfix-vX.X.X branch diff --git a/Gopkg.lock b/Gopkg.lock index cf5c97909..050569195 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -646,6 +646,7 @@ "github.com/tendermint/tendermint/rpc/lib/client", "github.com/tendermint/tendermint/rpc/lib/server", "github.com/tendermint/tendermint/types", + "github.com/tendermint/tendermint/version", "github.com/zondax/ledger-goclient", "golang.org/x/crypto/blowfish", "golang.org/x/crypto/ripemd160", diff --git a/Makefile b/Makefile index 6459f08e8..19a744d9f 100644 --- a/Makefile +++ b/Makefile @@ -93,6 +93,9 @@ update_tools: update_dev_tools: cd tools && $(MAKE) update_dev_tools +get_tools: + cd tools && $(MAKE) get_tools + get_dev_tools: cd tools && $(MAKE) get_dev_tools @@ -220,7 +223,7 @@ remotenet-status: # unless there is a reason not to. # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html .PHONY: build build_cosmos-sdk-cli build_examples install install_examples install_cosmos-sdk-cli install_debug dist \ -check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit \ +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 remotenet-start \ -remotenet-stop remotenet-status format check-ledger test_sim +remotenet-stop remotenet-status format check-ledger test_sim update_tools update_dev_tools diff --git a/PENDING.md b/PENDING.md index 31ba32350..49ceaf94c 100644 --- a/PENDING.md +++ b/PENDING.md @@ -2,8 +2,11 @@ BREAKING CHANGES * [baseapp] Msgs are no longer run on CheckTx, removed `ctx.IsCheckTx()` +* [x/gov] CLI flag changed from `proposalID` to `proposal-id` * [x/stake] Fixed the period check for the inflation calculation * [x/stake] Inflation doesn't use rationals in calculation (performance boost) +* [baseapp] NewBaseApp constructor now takes sdk.TxDecoder as argument instead of wire.Codec +* [x/auth] Default TxDecoder can be found in `x/auth` rather than baseapp * \#1606 The following CLI commands have been switched to use `--from` * `gaiacli stake create-validator --address-validator` * `gaiacli stake edit-validator --address-validator` @@ -16,6 +19,7 @@ BREAKING CHANGES * `gaiacli gov submit-proposal --proposer` * `gaiacli gov deposit --depositer` * `gaiacli gov vote --voter` +* [x/gov] Added tags sub-package, changed tags to use dash-case FEATURES * [lcd] Can now query governance proposals by ProposalStatus @@ -24,14 +28,17 @@ FEATURES * Modules can test random combinations of their own operations * Applications can integrate operations and invariants from modules together for an integrated simulation * [baseapp] Initialize validator set on ResponseInitChain -* Added support for cosmos-sdk-cli tool under cosmos-sdk/cmd - * This allows SDK users to init a new project repository with a single command. +* [cosmos-sdk-cli] Added support for cosmos-sdk-cli tool under cosmos-sdk/cmd + * This allows SDK users to initialize a new project repository. IMPROVEMENTS * [baseapp] Allow any alphanumeric character in route * [cli] Improve error messages for all txs when the account doesn't exist * [tools] Remove `rm -rf vendor/` from `make get_vendor_deps` +* [x/auth] Recover ErrorOutOfGas panic in order to set sdk.Result attributes correctly * [x/stake] Add revoked to human-readable validator +* [x/gov] Votes on a proposal can now be queried +* [x/bank] Unit tests are now table-driven BUG FIXES * \#1666 Add intra-tx counter to the genesis validators diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ca5e8fd97..048723755 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -18,7 +18,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/wire" - "github.com/cosmos/cosmos-sdk/x/auth" ) // Key to store the header in the DB itself. @@ -44,14 +43,12 @@ type BaseApp struct { // initialized on creation Logger log.Logger name string // application name from abci.Info - cdc *wire.Codec // Amino codec db dbm.DB // common DB backend cms sdk.CommitMultiStore // Main (uncached) state router Router // handle any kind of message codespacer *sdk.Codespacer // handle module codespacing + txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx - // must be set - txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx anteHandler sdk.AnteHandler // ante handler for fee and auth // may be nil @@ -80,17 +77,17 @@ var _ abci.Application = (*BaseApp)(nil) // (e.g. functional options). // // NOTE: The db is used to store the version number for now. +// Accepts a user-defined txDecoder // Accepts variable number of option functions, which act on the BaseApp to set configuration choices -func NewBaseApp(name string, cdc *wire.Codec, logger log.Logger, db dbm.DB, options ...func(*BaseApp)) *BaseApp { +func NewBaseApp(name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp)) *BaseApp { app := &BaseApp{ Logger: logger, name: name, - cdc: cdc, db: db, cms: store.NewCommitMultiStore(db), router: NewRouter(), codespacer: sdk.NewCodespacer(), - txDecoder: defaultTxDecoder(cdc), + txDecoder: txDecoder, } // Register the undefined & root codespaces, which should not be used by @@ -135,35 +132,6 @@ func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) { app.cms.MountStoreWithDB(key, typ, nil) } -// Set the txDecoder function -func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) { - app.txDecoder = txDecoder -} - -// default custom logic for transaction decoding -// TODO: remove auth and wire dependencies from baseapp -// - move this to auth.DefaultTxDecoder -// - set the default here to JSON decode like docs/examples/app1 (it will fail -// for multiple messages ;)) -// - pass a TxDecoder into NewBaseApp, instead of a codec. -func defaultTxDecoder(cdc *wire.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, sdk.Error) { - var tx = auth.StdTx{} - - if len(txBytes) == 0 { - return nil, sdk.ErrTxDecode("txBytes are empty") - } - - // StdTx.Msg is an interface. The concrete types - // are registered by MakeTxCodec - err := cdc.UnmarshalBinary(txBytes, &tx) - if err != nil { - return nil, sdk.ErrTxDecode("").TraceSDK(err.Error()) - } - return tx, nil - } -} - // nolint - Set functions func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) { app.initChainer = initChainer @@ -364,7 +332,9 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc default: result = sdk.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path)).Result() } - value := app.cdc.MustMarshalBinary(result) + + // Encode with json + value := wire.Cdc.MustMarshalBinary(result) return abci.ResponseQuery{ Code: uint32(sdk.ABCICodeOK), Value: value, diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index b2e0760ea..26e398b4e 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -30,7 +30,7 @@ func newBaseApp(name string) *BaseApp { db := dbm.NewMemDB() codec := wire.NewCodec() registerTestCodec(codec) - return NewBaseApp(name, codec, logger, db) + return NewBaseApp(name, logger, db, testTxDecoder(codec)) } func registerTestCodec(cdc *wire.Codec) { @@ -49,8 +49,6 @@ func setupBaseApp(t *testing.T) (*BaseApp, *sdk.KVStoreKey, *sdk.KVStoreKey) { app := newBaseApp(t.Name()) require.Equal(t, t.Name(), app.Name()) - app.SetTxDecoder(testTxDecoder(app.cdc)) - // make some cap keys capKey1 := sdk.NewKVStoreKey("key1") capKey2 := sdk.NewKVStoreKey("key2") @@ -85,7 +83,7 @@ func TestLoadVersion(t *testing.T) { logger := defaultLogger() db := dbm.NewMemDB() name := t.Name() - app := NewBaseApp(name, nil, logger, db) + app := NewBaseApp(name, logger, db, nil) // make a cap key and mount the store capKey := sdk.NewKVStoreKey("main") @@ -114,7 +112,7 @@ func TestLoadVersion(t *testing.T) { commitID2 := sdk.CommitID{2, res.Data} // reload with LoadLatestVersion - app = NewBaseApp(name, nil, logger, db) + app = NewBaseApp(name, logger, db, nil) app.MountStoresIAVL(capKey) err = app.LoadLatestVersion(capKey) require.Nil(t, err) @@ -122,7 +120,7 @@ func TestLoadVersion(t *testing.T) { // reload with LoadVersion, see if you can commit the same block and get // the same result - app = NewBaseApp(name, nil, logger, db) + app = NewBaseApp(name, logger, db, nil) app.MountStoresIAVL(capKey) err = app.LoadVersion(1, capKey) require.Nil(t, err) @@ -142,9 +140,7 @@ func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, exp func TestOptionFunction(t *testing.T) { logger := defaultLogger() db := dbm.NewMemDB() - codec := wire.NewCodec() - registerTestCodec(codec) - bap := NewBaseApp("starting name", codec, logger, db, testChangeNameHelper("new name")) + bap := NewBaseApp("starting name", logger, db, nil, testChangeNameHelper("new name")) require.Equal(t, bap.name, "new name", "BaseApp should have had name changed via option function") } @@ -216,7 +212,7 @@ func TestInitChainer(t *testing.T) { // we can reload the same app later db := dbm.NewMemDB() logger := defaultLogger() - app := NewBaseApp(name, nil, logger, db) + app := NewBaseApp(name, logger, db, nil) capKey := sdk.NewKVStoreKey("main") capKey2 := sdk.NewKVStoreKey("key2") app.MountStoresIAVL(capKey, capKey2) @@ -257,7 +253,7 @@ func TestInitChainer(t *testing.T) { require.Equal(t, value, res.Value) // reload app - app = NewBaseApp(name, nil, logger, db) + app = NewBaseApp(name, logger, db, nil) app.MountStoresIAVL(capKey, capKey2) err = app.LoadLatestVersion(capKey) // needed to make stores non-nil require.Nil(t, err) @@ -444,9 +440,13 @@ func TestCheckTx(t *testing.T) { app.InitChain(abci.RequestInitChain{}) + // Create same codec used in txDecoder + codec := wire.NewCodec() + registerTestCodec(codec) + for i := int64(0); i < nTxs; i++ { tx := newTxCounter(i, 0) - txBytes, err := app.cdc.MarshalBinary(tx) + txBytes, err := codec.MarshalBinary(tx) require.NoError(t, err) r := app.CheckTx(txBytes) assert.True(t, r.IsOK(), fmt.Sprintf("%v", r)) @@ -481,6 +481,10 @@ func TestDeliverTx(t *testing.T) { deliverKey := []byte("deliver-key") app.Router().AddRoute(typeMsgCounter, handlerMsgCounter(t, capKey, deliverKey)) + // Create same codec used in txDecoder + codec := wire.NewCodec() + registerTestCodec(codec) + nBlocks := 3 txPerHeight := 5 for blockN := 0; blockN < nBlocks; blockN++ { @@ -488,7 +492,7 @@ func TestDeliverTx(t *testing.T) { for i := 0; i < txPerHeight; i++ { counter := int64(blockN*txPerHeight + i) tx := newTxCounter(counter, counter) - txBytes, err := app.cdc.MarshalBinary(tx) + txBytes, err := codec.MarshalBinary(tx) require.NoError(t, err) res := app.DeliverTx(txBytes) require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) @@ -518,12 +522,16 @@ func TestMultiMsgDeliverTx(t *testing.T) { app.Router().AddRoute(typeMsgCounter, handlerMsgCounter(t, capKey, deliverKey)) app.Router().AddRoute(typeMsgCounter2, handlerMsgCounter(t, capKey, deliverKey2)) + // Create same codec used in txDecoder + codec := wire.NewCodec() + registerTestCodec(codec) + // run a multi-msg tx // with all msgs the same type { app.BeginBlock(abci.RequestBeginBlock{}) tx := newTxCounter(0, 0, 1, 2) - txBytes, err := app.cdc.MarshalBinary(tx) + txBytes, err := codec.MarshalBinary(tx) require.NoError(t, err) res := app.DeliverTx(txBytes) require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) @@ -544,7 +552,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 := app.cdc.MarshalBinary(tx) + txBytes, err := codec.MarshalBinary(tx) require.NoError(t, err) res := app.DeliverTx(txBytes) require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) @@ -589,6 +597,10 @@ func TestSimulateTx(t *testing.T) { }) app.InitChain(abci.RequestInitChain{}) + // Create same codec used in txDecoder + codec := wire.NewCodec() + registerTestCodec(codec) + nBlocks := 3 for blockN := 0; blockN < nBlocks; blockN++ { count := int64(blockN + 1) @@ -607,7 +619,7 @@ func TestSimulateTx(t *testing.T) { require.Equal(t, int64(gasConsumed), result.GasUsed) // simulate by calling Query with encoded tx - txBytes, err := app.cdc.MarshalBinary(tx) + txBytes, err := codec.MarshalBinary(tx) require.Nil(t, err) query := abci.RequestQuery{ Path: "/app/simulate", @@ -617,7 +629,8 @@ func TestSimulateTx(t *testing.T) { require.True(t, queryResult.IsOK(), queryResult.Log) var res sdk.Result - app.cdc.MustUnmarshalBinary(queryResult.Value, &res) + wire.Cdc.MustUnmarshalBinary(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) app.EndBlock(abci.RequestEndBlock{}) diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 2de92575a..b9efbc143 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -611,6 +611,17 @@ func TestProposalsQuery(t *testing.T) { // Test query voted and deposited by addr1 proposals = getProposalsFilterVoterDepositer(t, port, addr, addr) require.Equal(t, proposalID2, (proposals[0]).GetProposalID()) + + // Test query votes on Proposal 2 + votes := getVotes(t, port, proposalID2) + require.Len(t, votes, 1) + require.Equal(t, addr, votes[0].Voter) + + // Test query votes on Proposal 3 + votes = getVotes(t, port, proposalID3) + require.Len(t, votes, 2) + require.True(t, addr.String() == votes[0].Voter.String() || addr.String() == votes[1].Voter.String()) + require.True(t, addr2.String() == votes[0].Voter.String() || addr2.String() == votes[1].Voter.String()) } //_____________________________________________________________________________ @@ -875,6 +886,15 @@ 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 { + 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 + err := cdc.UnmarshalJSON([]byte(body), &votes) + require.Nil(t, err) + return votes +} + func getProposalsAll(t *testing.T, port string) []gov.Proposal { res, body := Request(t, port, "GET", "/gov/proposals", nil) require.Equal(t, http.StatusOK, res.StatusCode, body) diff --git a/cmd/cosmos-sdk-cli/cmd/init.go b/cmd/cosmos-sdk-cli/cmd/init.go index 5a0f3ddb3..d5d6422ad 100644 --- a/cmd/cosmos-sdk-cli/cmd/init.go +++ b/cmd/cosmos-sdk-cli/cmd/init.go @@ -44,9 +44,9 @@ var initCmd = &cobra.Command{ "basecoind", shortProjectName+"d", "BasecoinApp", capitalizedProjectName+"App", remoteBasecoinPath, remoteProjectPath, - "basecoin", shortProjectName) - setupBasecoinWorkspace(shortProjectName, remoteProjectPath) - return nil + "basecoin", shortProjectName, + "Basecoin", capitalizedProjectName) + return setupBasecoinWorkspace(shortProjectName, remoteProjectPath) }, } @@ -142,11 +142,16 @@ benchmark: } -func setupBasecoinWorkspace(projectName string, remoteProjectPath string) { +func setupBasecoinWorkspace(projectName string, remoteProjectPath string) error { projectPath := resolveProjectPath(remoteProjectPath) fmt.Println("Configuring your project in " + projectPath) + // Check if the projectPath already exists or not + if _, err := os.Stat(projectPath); !os.IsNotExist(err) { + return fmt.Errorf("Unable to initialize the project. %s already exists", projectPath) + } copyBasecoinTemplate(projectName, projectPath, remoteProjectPath) createGopkg(projectPath) createMakefile(projectPath) - fmt.Printf("\nInitialized a new project at %s.\nHappy hacking!\n", projectPath) + fmt.Printf("Initialized a new project at %s.\nHappy hacking!\n", projectPath) + return nil } diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index b0995da96..837ce5a10 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -63,7 +63,7 @@ type GaiaApp struct { func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp { cdc := MakeCodec() - bApp := bam.NewBaseApp(appName, cdc, logger, db, baseAppOptions...) + bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) var app = &GaiaApp{ diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index beac34097..e6ec2543f 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -188,35 +188,40 @@ func TestGaiaCLISubmitProposal(t *testing.T) { fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64()) - proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposalID=1 --output=json %v", flags)) + proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposal-id=1 --output=json %v", flags)) require.Equal(t, int64(1), proposal1.GetProposalID()) require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus()) depositStr := fmt.Sprintf("gaiacli gov deposit %v", flags) depositStr += fmt.Sprintf(" --from=%s", "foo") depositStr += fmt.Sprintf(" --deposit=%s", "10steak") - depositStr += fmt.Sprintf(" --proposalID=%s", "1") + depositStr += fmt.Sprintf(" --proposal-id=%s", "1") executeWrite(t, depositStr, pass) tests.WaitForNextNBlocksTM(2, port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64()) - proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposalID=1 --output=json %v", flags)) + proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposal-id=1 --output=json %v", flags)) require.Equal(t, int64(1), proposal1.GetProposalID()) require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus()) voteStr := fmt.Sprintf("gaiacli gov vote %v", flags) voteStr += fmt.Sprintf(" --from=%s", "foo") - voteStr += fmt.Sprintf(" --proposalID=%s", "1") + voteStr += fmt.Sprintf(" --proposal-id=%s", "1") voteStr += fmt.Sprintf(" --option=%s", "Yes") executeWrite(t, voteStr, pass) tests.WaitForNextNBlocksTM(2, port) - vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposalID=1 --voter=%s --output=json %v", fooAddr, flags)) + vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags)) require.Equal(t, int64(1), vote.ProposalID) require.Equal(t, gov.OptionYes, vote.Option) + + votes := executeGetVotes(t, fmt.Sprintf("gaiacli gov 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, gov.OptionYes, votes[0].Option) } //___________________________________________________________________________________ @@ -321,3 +326,12 @@ func executeGetVote(t *testing.T, cmdStr string) gov.Vote { require.NoError(t, err, "out %v\n, err %v", out, err) return vote } + +func executeGetVotes(t *testing.T, cmdStr string) []gov.Vote { + out := tests.ExecuteT(t, cmdStr) + var votes []gov.Vote + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(out), &votes) + require.NoError(t, err, "out %v\n, err %v", out, err) + return votes +} diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 4ab5d02b9..7c66cb9ef 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -112,6 +112,7 @@ func main() { client.GetCommands( govcmd.GetCmdQueryProposal("gov", cdc), govcmd.GetCmdQueryVote("gov", cdc), + govcmd.GetCmdQueryVotes("gov", cdc), )...) govCmd.AddCommand( client.PostCommands( diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index aa3bc939e..48878ebe6 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -149,7 +149,7 @@ type GaiaApp struct { func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp { cdc := MakeCodec() - bApp := bam.NewBaseApp(appName, cdc, logger, db, baseAppOptions...) + bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...) bApp.SetCommitMultiStoreTracer(os.Stdout) // create your application object diff --git a/cmd/gaia/testnets/STATUS.md b/cmd/gaia/testnets/STATUS.md index 185df94c6..442de16ec 100644 --- a/cmd/gaia/testnets/STATUS.md +++ b/cmd/gaia/testnets/STATUS.md @@ -1,5 +1,10 @@ # TESTNET STATUS +## *July 22, 2018, 5:30 EST* - Gaia-7001 Consensus Failure + +- [Consensus Failure at Block 24570](https://github.com/cosmos/cosmos-sdk/issues/1787) + + ## *July 17, 2018, 4:00 EST* - New Testnet Gaia-7001 - New testnet with fixes for the genesis file diff --git a/docs/sdk/core/app1.md b/docs/sdk/core/app1.md index 6977d2ddc..ddf2a533e 100644 --- a/docs/sdk/core/app1.md +++ b/docs/sdk/core/app1.md @@ -421,17 +421,13 @@ Here is the complete setup for App1: ```go func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { - cdc := wire.NewCodec() // Create the base application object. - app := bapp.NewBaseApp(app1Name, cdc, logger, db) + app := bapp.NewBaseApp(app1Name, logger, db, tx1Decoder) // Create a capability key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") - // Determine how transactions are decoded. - app.SetTxDecoder(txDecoder) - // Register message routes. // Note the handler receives the keyAccount and thus // gets access to the account store. @@ -458,7 +454,7 @@ Here, we have only a single Msg type, `bank`, a single store for accounts, and a The handler is granted access to the store by giving it the capability key. In future apps, we'll have multiple stores and handlers, and not every handler will get access to every store. -After setting the transaction decoder and the message handling routes, the final +After setting the message handling routes, the final step is to mount the stores and load the latest version. Since we only have one store, we only mount one. diff --git a/docs/sdk/core/app2.md b/docs/sdk/core/app2.md index 0158976cd..1f9e81a31 100644 --- a/docs/sdk/core/app2.md +++ b/docs/sdk/core/app2.md @@ -169,10 +169,19 @@ type app2Tx struct { func (tx app2Tx) GetMsgs() []sdk.Msg { return []sdk.Msg{tx.Msg} } -``` -We don't need a custom TxDecoder function anymore, since we're just using the -Amino codec! +// Amino decode app2Tx. Capable of decoding both MsgSend and MsgIssue +func tx2Decoder(cdc *wire.Codec) sdk.TxDecoder { + return func(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx app2Tx + err := cdc.UnmarshalBinary(txBytes, &tx) + if err != nil { + return nil, sdk.ErrTxDecode(err.Error()) + } + return tx, nil + } +} +``` ## AnteHandler @@ -249,7 +258,7 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { cdc := NewCodec() // Create the base application object. - app := bapp.NewBaseApp(app2Name, cdc, logger, db) + app := bapp.NewBaseApp(app2Name, logger, db, txDecoder(cdc)) // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") @@ -280,9 +289,8 @@ key for a second store that is *only* passed to a second handler, the `handleMsgIssue`. The first `handleMsgSend` has no access to this second store and cannot read or write to it, ensuring a strong separation of concerns. -Note also that we do not need to use `SetTxDecoder` here - now that we're using -Amino, we simply create a codec, register our types on the codec, and pass the -codec into `NewBaseApp`. The SDK takes care of the rest for us! +Note now that we're using Amino, we create a codec, register our types on the codec, and pass the +codec into our TxDecoder constructor, `tx2Decoder`. The SDK takes care of the rest for us! ## Conclusion diff --git a/docs/sdk/core/app3.md b/docs/sdk/core/app3.md index 459f48c83..66bb05521 100644 --- a/docs/sdk/core/app3.md +++ b/docs/sdk/core/app3.md @@ -328,7 +328,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { cdc := NewCodec() // Create the base application object. - app := bapp.NewBaseApp(app3Name, cdc, logger, db) + app := bapp.NewBaseApp(app3Name, logger, db, auth.DefaultTxDecoder(cdc)) // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") @@ -361,6 +361,9 @@ and receives only the `bank.Keeper`. See the [x/bank API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank) for more details. +We also use the default txDecoder in `x/auth`, which decodes amino-encoded +`auth.StdTx` transactions. + ## Conclusion Armed with native modules for authentication and coin transfer, diff --git a/docs/sdk/core/examples/app1.go b/docs/sdk/core/examples/app1.go index b208f75cf..ba33c6120 100644 --- a/docs/sdk/core/examples/app1.go +++ b/docs/sdk/core/examples/app1.go @@ -9,7 +9,6 @@ import ( bapp "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" ) const ( @@ -18,17 +17,12 @@ const ( func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp { - cdc := wire.NewCodec() - // Create the base application object. - app := bapp.NewBaseApp(app1Name, cdc, logger, db) + app := bapp.NewBaseApp(app1Name, logger, db, tx1Decoder) // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") - // Determine how transactions are decoded. - app.SetTxDecoder(txDecoder) - // Register message routes. // Note the handler gets access to the account store. app.Router(). @@ -225,7 +219,7 @@ func (tx app1Tx) GetMsgs() []sdk.Msg { } // JSON decode MsgSend. -func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { +func tx1Decoder(txBytes []byte) (sdk.Tx, sdk.Error) { var tx app1Tx err := json.Unmarshal(txBytes, &tx) if err != nil { diff --git a/docs/sdk/core/examples/app2.go b/docs/sdk/core/examples/app2.go index 4c20c17c3..1e1910b62 100644 --- a/docs/sdk/core/examples/app2.go +++ b/docs/sdk/core/examples/app2.go @@ -37,7 +37,7 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp { cdc := NewCodec() // Create the base application object. - app := bapp.NewBaseApp(app2Name, cdc, logger, db) + app := bapp.NewBaseApp(app2Name, logger, db, tx2Decoder(cdc)) // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") @@ -191,6 +191,18 @@ func (tx app2Tx) GetSignatures() []auth.StdSignature { return tx.Signatures } +// Amino decode app2Tx. Capable of decoding both MsgSend and MsgIssue +func tx2Decoder(cdc *wire.Codec) sdk.TxDecoder { + return func(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx app2Tx + err := cdc.UnmarshalBinary(txBytes, &tx) + if err != nil { + return nil, sdk.ErrTxDecode(err.Error()) + } + return tx, nil + } +} + //------------------------------------------------------------------ // Simple anteHandler that ensures msg signers have signed. diff --git a/docs/sdk/core/examples/app3.go b/docs/sdk/core/examples/app3.go index 853ad687e..15c8ea758 100644 --- a/docs/sdk/core/examples/app3.go +++ b/docs/sdk/core/examples/app3.go @@ -21,7 +21,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp { cdc := NewCodec() // Create the base application object. - app := bapp.NewBaseApp(app3Name, cdc, logger, db) + app := bapp.NewBaseApp(app3Name, logger, db, auth.DefaultTxDecoder(cdc)) // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") diff --git a/docs/sdk/core/examples/app4.go b/docs/sdk/core/examples/app4.go index a8ef37cee..f8175fe41 100644 --- a/docs/sdk/core/examples/app4.go +++ b/docs/sdk/core/examples/app4.go @@ -22,7 +22,7 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp { cdc := NewCodec() // Create the base application object. - app := bapp.NewBaseApp(app3Name, cdc, logger, db) + app := bapp.NewBaseApp(app4Name, logger, db, auth.DefaultTxDecoder(cdc)) // Create a key for accessing the account store. keyAccount := sdk.NewKVStoreKey("acc") diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index 14d4550d3..aa3ea2590 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -53,7 +53,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.Ba // create your application type var app = &BasecoinApp{ cdc: cdc, - BaseApp: bam.NewBaseApp(appName, cdc, logger, db, baseAppOptions...), + BaseApp: bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...), keyMain: sdk.NewKVStoreKey("main"), keyAccount: sdk.NewKVStoreKey("acc"), keyIBC: sdk.NewKVStoreKey("ibc"), diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 51d10002a..4d4afb92d 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -58,7 +58,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { // Create your application object. var app = &DemocoinApp{ - BaseApp: bam.NewBaseApp(appName, cdc, logger, db), + BaseApp: bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc)), cdc: cdc, capKeyMainStore: sdk.NewKVStoreKey("main"), capKeyAccountStore: sdk.NewKVStoreKey("acc"), diff --git a/examples/kvstore/main.go b/examples/kvstore/main.go index 47416da05..125c7cd47 100644 --- a/examples/kvstore/main.go +++ b/examples/kvstore/main.go @@ -32,14 +32,11 @@ func main() { var capKeyMainStore = sdk.NewKVStoreKey("main") // Create BaseApp. - var baseApp = bam.NewBaseApp("kvstore", nil, logger, db) + var baseApp = bam.NewBaseApp("kvstore", logger, db, decodeTx) // Set mounts for BaseApp's MultiStore. baseApp.MountStoresIAVL(capKeyMainStore) - // Set Tx decoder - baseApp.SetTxDecoder(decodeTx) - // Set a handler Route. baseApp.Router().AddRoute("kvstore", Handler(capKeyMainStore)) diff --git a/server/mock/app.go b/server/mock/app.go index 5229da41e..7b22328b0 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -30,14 +30,11 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) { capKeyMainStore := sdk.NewKVStoreKey("main") // Create BaseApp. - baseApp := bam.NewBaseApp("kvstore", nil, logger, db) + baseApp := bam.NewBaseApp("kvstore", logger, db, decodeTx) // Set mounts for BaseApp's MultiStore. baseApp.MountStoresIAVL(capKeyMainStore) - // Set Tx decoder - baseApp.SetTxDecoder(decodeTx) - baseApp.SetInitChainer(InitChainer(capKeyMainStore)) // Set a handler Route. diff --git a/x/auth/ante.go b/x/auth/ante.go index 9652b37de..60aea8fc7 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -17,11 +17,12 @@ const ( // NewAnteHandler returns an AnteHandler that checks // and increments sequence numbers, checks signatures & account numbers, // and deducts fees from the first signer. +// nolint: gocyclo func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { return func( ctx sdk.Context, tx sdk.Tx, - ) (_ sdk.Context, _ sdk.Result, abort bool) { + ) (newCtx sdk.Context, res sdk.Result, abort bool) { // This AnteHandler requires Txs to be StdTxs stdTx, ok := tx.(StdTx) @@ -29,20 +30,39 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { return ctx, sdk.ErrInternal("tx must be StdTx").Result(), true } + // set the gas meter + newCtx = ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas)) + + // AnteHandlers must have their own defer/recover in order + // for the BaseApp to know how much gas was used! + // This is because the GasMeter is created in the AnteHandler, + // but if it panics the context won't be set properly in runTx's recover ... + defer func() { + if r := recover(); r != nil { + switch rType := r.(type) { + case sdk.ErrorOutOfGas: + log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor) + res = sdk.ErrOutOfGas(log).Result() + res.GasWanted = stdTx.Fee.Gas + res.GasUsed = newCtx.GasMeter().GasConsumed() + abort = true + default: + panic(r) + } + } + }() + err := validateBasic(stdTx) if err != nil { - return ctx, err.Result(), true + return newCtx, err.Result(), true } sigs := stdTx.GetSignatures() signerAddrs := stdTx.GetSigners() msgs := tx.GetMsgs() - // set the gas meter - ctx = ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas)) - // charge gas for the memo - ctx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo") + newCtx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo") // Get the sign bytes (requires all account & sequence numbers and the fee) sequences := make([]int64, len(sigs)) @@ -59,38 +79,38 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler { signerAddr, sig := signerAddrs[i], sigs[i] // check signature, return account with incremented nonce - signBytes := StdSignBytes(ctx.ChainID(), accNums[i], sequences[i], fee, msgs, stdTx.GetMemo()) + signBytes := StdSignBytes(newCtx.ChainID(), accNums[i], sequences[i], fee, msgs, stdTx.GetMemo()) signerAcc, res := processSig( - ctx, am, + newCtx, am, signerAddr, sig, signBytes, ) if !res.IsOK() { - return ctx, res, true + return newCtx, res, true } // first sig pays the fees // TODO: Add min fees // Can this function be moved outside of the loop? if i == 0 && !fee.Amount.IsZero() { - ctx.GasMeter().ConsumeGas(deductFeesCost, "deductFees") + newCtx.GasMeter().ConsumeGas(deductFeesCost, "deductFees") signerAcc, res = deductFees(signerAcc, fee) if !res.IsOK() { - return ctx, res, true + return newCtx, res, true } - fck.addCollectedFees(ctx, fee.Amount) + fck.addCollectedFees(newCtx, fee.Amount) } // Save the account. - am.SetAccount(ctx, signerAcc) + am.SetAccount(newCtx, signerAcc) signerAccs[i] = signerAcc } // cache the signer accounts in the context - ctx = WithSigners(ctx, signerAccs) + newCtx = WithSigners(newCtx, signerAccs) // TODO: tx tags (?) - return ctx, sdk.Result{}, false // continue... + return newCtx, sdk.Result{GasWanted: stdTx.Fee.Gas}, false // continue... } } diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index c30013d32..907de1749 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -47,21 +47,20 @@ func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx // run the tx through the anteHandler and ensure it fails with the given code func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, code sdk.CodeType) { - defer func() { - if r := recover(); r != nil { - switch r.(type) { - case sdk.ErrorOutOfGas: - require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOutOfGas), - fmt.Sprintf("Expected ErrorOutOfGas, got %v", r)) - default: - panic(r) - } - } - }() - _, result, abort := anteHandler(ctx, tx) + newCtx, result, abort := anteHandler(ctx, tx) require.True(t, abort) require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code, fmt.Sprintf("Expected %v, got %v", sdk.ToABCICode(sdk.CodespaceRoot, code), result)) + + if code == sdk.CodeOutOfGas { + stdTx, ok := tx.(StdTx) + require.True(t, ok, "tx must be in form auth.StdTx") + // GasWanted set correctly + require.Equal(t, stdTx.Fee.Gas, result.GasWanted, "Gas wanted not set correctly") + require.True(t, result.GasUsed > result.GasWanted, "GasUsed not greated than GasWanted") + // Check that context is set correctly + require.Equal(t, result.GasUsed, newCtx.GasMeter().GasConsumed(), "Context not updated correctly") + } } func newTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee) sdk.Tx { diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index 316ff5e95..bebd24623 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -4,6 +4,7 @@ import ( "encoding/json" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" "github.com/tendermint/tendermint/crypto" ) @@ -162,3 +163,22 @@ type StdSignature struct { AccountNumber int64 `json:"account_number"` Sequence int64 `json:"sequence"` } + +// logic for standard transaction decoding +func DefaultTxDecoder(cdc *wire.Codec) sdk.TxDecoder { + return func(txBytes []byte) (sdk.Tx, sdk.Error) { + var tx = StdTx{} + + if len(txBytes) == 0 { + return nil, sdk.ErrTxDecode("txBytes are empty") + } + + // StdTx.Msg is an interface. The concrete types + // are registered by MakeTxCodec + err := cdc.UnmarshalBinary(txBytes, &tx) + if err != nil { + return nil, sdk.ErrTxDecode("").TraceSDK(err.Error()) + } + return tx, nil + } +} diff --git a/x/bank/app_test.go b/x/bank/app_test.go index 2deb5de38..8b6968eb9 100644 --- a/x/bank/app_test.go +++ b/x/bank/app_test.go @@ -3,39 +3,50 @@ package bank import ( "testing" - "github.com/stretchr/testify/require" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/mock" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" ) -// test bank module in a mock application +type ( + expectedBalance struct { + addr sdk.AccAddress + coins sdk.Coins + } + + appTestCase struct { + expPass bool + msgs []sdk.Msg + accNums []int64 + accSeqs []int64 + privKeys []crypto.PrivKey + expectedBalances []expectedBalance + } +) + var ( - priv1 = crypto.GenPrivKeyEd25519() - addr1 = sdk.AccAddress(priv1.PubKey().Address()) - priv2 = crypto.GenPrivKeyEd25519() - addr2 = sdk.AccAddress(priv2.PubKey().Address()) - addr3 = sdk.AccAddress(crypto.GenPrivKeyEd25519().PubKey().Address()) - priv4 = crypto.GenPrivKeyEd25519() - addr4 = sdk.AccAddress(priv4.PubKey().Address()) + priv1 = crypto.GenPrivKeyEd25519() + addr1 = sdk.AccAddress(priv1.PubKey().Address()) + priv2 = crypto.GenPrivKeyEd25519() + addr2 = sdk.AccAddress(priv2.PubKey().Address()) + addr3 = sdk.AccAddress(crypto.GenPrivKeyEd25519().PubKey().Address()) + priv4 = crypto.GenPrivKeyEd25519() + addr4 = sdk.AccAddress(priv4.PubKey().Address()) + coins = sdk.Coins{sdk.NewCoin("foocoin", 10)} halfCoins = sdk.Coins{sdk.NewCoin("foocoin", 5)} manyCoins = sdk.Coins{sdk.NewCoin("foocoin", 1), sdk.NewCoin("barcoin", 1)} - - freeFee = auth.StdFee{ // no fees for a buncha gas - sdk.Coins{sdk.NewCoin("foocoin", 0)}, - 100000, - } + freeFee = auth.NewStdFee(100000, sdk.Coins{sdk.NewCoin("foocoin", 0)}...) sendMsg1 = MsgSend{ Inputs: []Input{NewInput(addr1, coins)}, Outputs: []Output{NewOutput(addr2, coins)}, } - sendMsg2 = MsgSend{ Inputs: []Input{NewInput(addr1, coins)}, Outputs: []Output{ @@ -43,7 +54,6 @@ var ( NewOutput(addr3, halfCoins), }, } - sendMsg3 = MsgSend{ Inputs: []Input{ NewInput(addr1, coins), @@ -54,7 +64,6 @@ var ( NewOutput(addr3, coins), }, } - sendMsg4 = MsgSend{ Inputs: []Input{ NewInput(addr2, coins), @@ -63,7 +72,6 @@ var ( NewOutput(addr1, coins), }, } - sendMsg5 = MsgSend{ Inputs: []Input{ NewInput(addr1, manyCoins), @@ -83,39 +91,55 @@ func getMockApp(t *testing.T) *mock.App { func TestMsgSendWithAccounts(t *testing.T) { mapp := getMockApp(t) - - // Add an account at genesis acc := &auth.BaseAccount{ Address: addr1, Coins: sdk.Coins{sdk.NewCoin("foocoin", 67)}, } - accs := []auth.Account{acc} - // Construct genesis state - mock.SetGenesis(mapp, accs) + mock.SetGenesis(mapp, []auth.Account{acc}) - // A checkTx context (true) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) + res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1) require.NotNil(t, res1) require.Equal(t, acc, res1.(*auth.BaseAccount)) - // Run a CheckDeliver - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1}, []int64{0}, []int64{0}, true, priv1) + testCases := []appTestCase{ + { + msgs: []sdk.Msg{sendMsg1}, + accNums: []int64{0}, + accSeqs: []int64{0}, + expPass: true, + privKeys: []crypto.PrivKey{priv1}, + expectedBalances: []expectedBalance{ + expectedBalance{addr1, sdk.Coins{sdk.NewCoin("foocoin", 57)}}, + expectedBalance{addr2, sdk.Coins{sdk.NewCoin("foocoin", 10)}}, + }, + }, + { + msgs: []sdk.Msg{sendMsg1, sendMsg2}, + accNums: []int64{0}, + accSeqs: []int64{0}, + expPass: false, + privKeys: []crypto.PrivKey{priv1}, + }, + } - // Check balances - mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("foocoin", 57)}) - mock.CheckBalance(t, mapp, addr2, sdk.Coins{sdk.NewCoin("foocoin", 10)}) + for _, tc := range testCases { + mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...) - // Delivering again should cause replay error - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1, sendMsg2}, []int64{0}, []int64{0}, false, priv1) + for _, eb := range tc.expectedBalances { + mock.CheckBalance(t, mapp, eb.addr, eb.coins) + } + } - // bumping the txnonce number without resigning should be an auth error + // bumping the tx nonce number without resigning should be an auth error mapp.BeginBlock(abci.RequestBeginBlock{}) + tx := mock.GenTx([]sdk.Msg{sendMsg1}, []int64{0}, []int64{0}, priv1) tx.Signatures[0].Sequence = 1 - res := mapp.Deliver(tx) + res := mapp.Deliver(tx) require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) // resigning the tx with the bumped sequence should work @@ -129,22 +153,35 @@ func TestMsgSendMultipleOut(t *testing.T) { Address: addr1, Coins: sdk.Coins{sdk.NewCoin("foocoin", 42)}, } - acc2 := &auth.BaseAccount{ Address: addr2, Coins: sdk.Coins{sdk.NewCoin("foocoin", 42)}, } - accs := []auth.Account{acc1, acc2} - mock.SetGenesis(mapp, accs) + mock.SetGenesis(mapp, []auth.Account{acc1, acc2}) - // Simulate a Block - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg2}, []int64{0}, []int64{0}, true, priv1) + testCases := []appTestCase{ + { + msgs: []sdk.Msg{sendMsg2}, + accNums: []int64{0}, + accSeqs: []int64{0}, + expPass: true, + privKeys: []crypto.PrivKey{priv1}, + expectedBalances: []expectedBalance{ + expectedBalance{addr1, sdk.Coins{sdk.NewCoin("foocoin", 32)}}, + expectedBalance{addr2, sdk.Coins{sdk.NewCoin("foocoin", 47)}}, + expectedBalance{addr3, sdk.Coins{sdk.NewCoin("foocoin", 5)}}, + }, + }, + } - // Check balances - mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("foocoin", 32)}) - mock.CheckBalance(t, mapp, addr2, sdk.Coins{sdk.NewCoin("foocoin", 47)}) - mock.CheckBalance(t, mapp, addr3, sdk.Coins{sdk.NewCoin("foocoin", 5)}) + for _, tc := range testCases { + mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...) + + for _, eb := range tc.expectedBalances { + mock.CheckBalance(t, mapp, eb.addr, eb.coins) + } + } } func TestSengMsgMultipleInOut(t *testing.T) { @@ -162,18 +199,32 @@ func TestSengMsgMultipleInOut(t *testing.T) { Address: addr4, Coins: sdk.Coins{sdk.NewCoin("foocoin", 42)}, } - accs := []auth.Account{acc1, acc2, acc4} - mock.SetGenesis(mapp, accs) + mock.SetGenesis(mapp, []auth.Account{acc1, acc2, acc4}) - // CheckDeliver - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg3}, []int64{0, 2}, []int64{0, 0}, true, priv1, priv4) + testCases := []appTestCase{ + { + msgs: []sdk.Msg{sendMsg3}, + accNums: []int64{0, 2}, + accSeqs: []int64{0, 0}, + expPass: true, + privKeys: []crypto.PrivKey{priv1, priv4}, + expectedBalances: []expectedBalance{ + expectedBalance{addr1, sdk.Coins{sdk.NewCoin("foocoin", 32)}}, + expectedBalance{addr4, sdk.Coins{sdk.NewCoin("foocoin", 32)}}, + expectedBalance{addr2, sdk.Coins{sdk.NewCoin("foocoin", 52)}}, + expectedBalance{addr3, sdk.Coins{sdk.NewCoin("foocoin", 10)}}, + }, + }, + } - // Check balances - mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("foocoin", 32)}) - mock.CheckBalance(t, mapp, addr4, sdk.Coins{sdk.NewCoin("foocoin", 32)}) - mock.CheckBalance(t, mapp, addr2, sdk.Coins{sdk.NewCoin("foocoin", 52)}) - mock.CheckBalance(t, mapp, addr3, sdk.Coins{sdk.NewCoin("foocoin", 10)}) + for _, tc := range testCases { + mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...) + + for _, eb := range tc.expectedBalances { + mock.CheckBalance(t, mapp, eb.addr, eb.coins) + } + } } func TestMsgSendDependent(t *testing.T) { @@ -183,20 +234,38 @@ func TestMsgSendDependent(t *testing.T) { Address: addr1, Coins: sdk.Coins{sdk.NewCoin("foocoin", 42)}, } - accs := []auth.Account{acc1} - mock.SetGenesis(mapp, accs) + mock.SetGenesis(mapp, []auth.Account{acc1}) - // CheckDeliver - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1}, []int64{0}, []int64{0}, true, priv1) + testCases := []appTestCase{ + { + msgs: []sdk.Msg{sendMsg1}, + accNums: []int64{0}, + accSeqs: []int64{0}, + expPass: true, + privKeys: []crypto.PrivKey{priv1}, + expectedBalances: []expectedBalance{ + expectedBalance{addr1, sdk.Coins{sdk.NewCoin("foocoin", 32)}}, + expectedBalance{addr2, sdk.Coins{sdk.NewCoin("foocoin", 10)}}, + }, + }, + { + msgs: []sdk.Msg{sendMsg4}, + accNums: []int64{1}, + accSeqs: []int64{0}, + expPass: true, + privKeys: []crypto.PrivKey{priv2}, + expectedBalances: []expectedBalance{ + expectedBalance{addr1, sdk.Coins{sdk.NewCoin("foocoin", 42)}}, + }, + }, + } - // Check balances - mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("foocoin", 32)}) - mock.CheckBalance(t, mapp, addr2, sdk.Coins{sdk.NewCoin("foocoin", 10)}) + for _, tc := range testCases { + mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...) - // Simulate a Block - mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg4}, []int64{1}, []int64{0}, true, priv2) - - // Check balances - mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("foocoin", 42)}) + for _, eb := range tc.expectedBalances { + mock.CheckBalance(t, mapp, eb.addr, eb.coins) + } + } } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index c1bb62bc7..45b49a542 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -15,7 +15,7 @@ import ( ) const ( - flagProposalID = "proposalID" + flagProposalID = "proposal-id" flagTitle = "title" flagDescription = "description" flagProposalType = "type" @@ -239,3 +239,54 @@ func GetCmdQueryVote(storeName string, cdc *wire.Codec) *cobra.Command { return cmd } + +// Command to Get a Proposal Information +func GetCmdQueryVotes(storeName string, cdc *wire.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "query-votes", + Short: "query votes on a proposal", + RunE: func(cmd *cobra.Command, args []string) error { + proposalID := viper.GetInt64(flagProposalID) + + ctx := context.NewCoreContextFromViper() + + res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + if len(res) == 0 || err != nil { + return errors.Errorf("proposalID [%d] does not exist", proposalID) + } + + var proposal gov.Proposal + cdc.MustUnmarshalBinary(res, &proposal) + + if proposal.GetStatus() != gov.StatusVotingPeriod { + fmt.Println("Proposal not in voting period.") + return nil + } + + res2, err := ctx.QuerySubspace(cdc, gov.KeyVotesSubspace(proposalID), storeName) + if err != nil { + return err + } + + var votes []gov.Vote + for i := 0; i < len(res2); i++ { + var vote gov.Vote + cdc.MustUnmarshalBinary(res2[i].Value, &vote) + votes = append(votes, vote) + } + + output, err := wire.MarshalJSONIndent(cdc, votes) + if err != nil { + return err + } + + fmt.Println(string(output)) + + return nil + }, + } + + cmd.Flags().String(flagProposalID, "", "proposalID of which proposal's votes are being queried") + + return cmd +} diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index ffaf42749..7efce9f0b 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -33,6 +33,8 @@ func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) { r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn(cdc)).Methods("GET") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes/{%s}", RestProposalID, RestVoter), queryVoteHandlerFn(cdc)).Methods("GET") + r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), queryVotesOnProposalHandlerFn(cdc)).Methods("GET") + r.HandleFunc("/gov/proposals", queryProposalsWithParameterFn(cdc)).Methods("GET") } @@ -335,6 +337,71 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc { } } +// nolint: gocyclo +// todo: Split this functionality into helper functions to remove the above +func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + strProposalID := vars[RestProposalID] + + if len(strProposalID) == 0 { + w.WriteHeader(http.StatusBadRequest) + err := errors.New("proposalId required but not specified") + w.Write([]byte(err.Error())) + return + } + + proposalID, err := strconv.ParseInt(strProposalID, 10, 64) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + err := errors.Errorf("proposalID [%s] is not positive", proposalID) + w.Write([]byte(err.Error())) + return + } + + ctx := context.NewCoreContextFromViper() + + res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName) + if err != nil || len(res) == 0 { + err := errors.Errorf("proposalID [%d] does not exist", proposalID) + w.Write([]byte(err.Error())) + return + } + + var proposal gov.Proposal + cdc.MustUnmarshalBinary(res, &proposal) + + if proposal.GetStatus() != gov.StatusVotingPeriod { + err := errors.Errorf("proposal is not in Voting Period", proposalID) + w.Write([]byte(err.Error())) + return + } + + res2, err := ctx.QuerySubspace(cdc, gov.KeyVotesSubspace(proposalID), storeName) + if err != nil { + err = errors.New("ProposalID doesn't exist") + w.Write([]byte(err.Error())) + return + } + + var votes []gov.Vote + + for i := 0; i < len(res2); i++ { + var vote gov.Vote + cdc.MustUnmarshalBinary(res2[i].Value, &vote) + votes = append(votes, vote) + } + + output, err := wire.MarshalJSONIndent(cdc, votes) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + w.Write(output) + } +} + // nolint: gocyclo // todo: Split this functionality into helper functions to remove the above func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc { diff --git a/x/gov/handler.go b/x/gov/handler.go index 636454571..04a68ccbb 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -2,6 +2,7 @@ package gov import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/tags" ) // Handle all "gov" type messages. @@ -32,19 +33,19 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(proposal.GetProposalID()) - tags := sdk.NewTags( - "action", []byte("submitProposal"), - "proposer", []byte(msg.Proposer.String()), - "proposalId", proposalIDBytes, + resTags := sdk.NewTags( + tags.Action, tags.ActionSubmitProposal, + tags.Proposer, []byte(msg.Proposer.String()), + tags.ProposalID, proposalIDBytes, ) if votingStarted { - tags.AppendTag("votingPeriodStart", proposalIDBytes) + resTags.AppendTag(tags.VotingPeriodStart, proposalIDBytes) } return sdk.Result{ Data: proposalIDBytes, - Tags: tags, + Tags: resTags, } } @@ -58,18 +59,18 @@ func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) sdk.Result proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(msg.ProposalID) // TODO: Add tag for if voting period started - tags := sdk.NewTags( - "action", []byte("deposit"), - "depositer", []byte(msg.Depositer.String()), - "proposalId", proposalIDBytes, + resTags := sdk.NewTags( + tags.Action, tags.ActionDeposit, + tags.Depositer, []byte(msg.Depositer.String()), + tags.ProposalID, proposalIDBytes, ) if votingStarted { - tags.AppendTag("votingPeriodStart", proposalIDBytes) + resTags.AppendTag(tags.VotingPeriodStart, proposalIDBytes) } return sdk.Result{ - Tags: tags, + Tags: resTags, } } @@ -82,30 +83,32 @@ func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) sdk.Result { proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(msg.ProposalID) - tags := sdk.NewTags( - "action", []byte("vote"), - "voter", []byte(msg.Voter.String()), - "proposalId", proposalIDBytes, + resTags := sdk.NewTags( + tags.Action, tags.ActionVote, + tags.Voter, []byte(msg.Voter.String()), + tags.ProposalID, proposalIDBytes, ) return sdk.Result{ - Tags: tags, + Tags: resTags, } } // Called every block, process inflation, update validator set -func EndBlocker(ctx sdk.Context, keeper Keeper) (tags sdk.Tags, nonVotingVals []sdk.AccAddress) { +func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags, nonVotingVals []sdk.AccAddress) { - tags = sdk.NewTags() + resTags = sdk.NewTags() // Delete proposals that haven't met minDeposit for shouldPopInactiveProposalQueue(ctx, keeper) { inactiveProposal := keeper.InactiveProposalQueuePop(ctx) - if inactiveProposal.GetStatus() == StatusDepositPeriod { - proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(inactiveProposal.GetProposalID()) - keeper.DeleteProposal(ctx, inactiveProposal) - tags.AppendTag("action", []byte("proposalDropped")) - tags.AppendTag("proposalId", proposalIDBytes) + if inactiveProposal.GetStatus() != StatusDepositPeriod { + continue } + + proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(inactiveProposal.GetProposalID()) + keeper.DeleteProposal(ctx, inactiveProposal) + resTags.AppendTag(tags.Action, tags.ActionProposalDropped) + resTags.AppendTag(tags.ProposalID, proposalIDBytes) } var passes bool @@ -114,26 +117,31 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (tags sdk.Tags, nonVotingVals [] for shouldPopActiveProposalQueue(ctx, keeper) { activeProposal := keeper.ActiveProposalQueuePop(ctx) - if ctx.BlockHeight() >= activeProposal.GetVotingStartBlock()+keeper.GetVotingProcedure().VotingPeriod { - passes, nonVotingVals = tally(ctx, keeper, activeProposal) - proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(activeProposal.GetProposalID()) - if passes { - keeper.RefundDeposits(ctx, activeProposal.GetProposalID()) - activeProposal.SetStatus(StatusPassed) - tags.AppendTag("action", []byte("proposalPassed")) - tags.AppendTag("proposalId", proposalIDBytes) - } else { - keeper.DeleteDeposits(ctx, activeProposal.GetProposalID()) - activeProposal.SetStatus(StatusRejected) - tags.AppendTag("action", []byte("proposalRejected")) - tags.AppendTag("proposalId", proposalIDBytes) - } - - keeper.SetProposal(ctx, activeProposal) + proposalStartBlock := activeProposal.GetVotingStartBlock() + votingPeriod := keeper.GetVotingProcedure().VotingPeriod + if ctx.BlockHeight() < proposalStartBlock+votingPeriod { + continue } + + passes, nonVotingVals = tally(ctx, keeper, activeProposal) + proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(activeProposal.GetProposalID()) + var action []byte + if passes { + keeper.RefundDeposits(ctx, activeProposal.GetProposalID()) + activeProposal.SetStatus(StatusPassed) + action = tags.ActionProposalPassed + } else { + keeper.DeleteDeposits(ctx, activeProposal.GetProposalID()) + activeProposal.SetStatus(StatusRejected) + action = tags.ActionProposalRejected + } + keeper.SetProposal(ctx, activeProposal) + + resTags.AppendTag(tags.Action, action) + resTags.AppendTag(tags.ProposalID, proposalIDBytes) } - return tags, nonVotingVals + return resTags, nonVotingVals } func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { depositProcedure := keeper.GetDepositProcedure() diff --git a/x/gov/tags/tags.go b/x/gov/tags/tags.go new file mode 100644 index 000000000..2eded1901 --- /dev/null +++ b/x/gov/tags/tags.go @@ -0,0 +1,22 @@ +// nolint +package tags + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + ActionSubmitProposal = []byte("submit-proposal") + ActionDeposit = []byte("deposit") + ActionVote = []byte("vote") + ActionProposalDropped = []byte("proposal-dropped") + ActionProposalPassed = []byte("proposal-passed") + ActionProposalRejected = []byte("proposal-rejected") + + Action = sdk.TagAction + Proposer = "proposer" + ProposalID = "proposal-id" + VotingPeriodStart = "voting-period-start" + Depositer = "depositer" + Voter = "voter" +) diff --git a/x/mock/app.go b/x/mock/app.go index 175222fa8..a18383f2b 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -47,7 +47,7 @@ func NewApp() *App { // Create your application object app := &App{ - BaseApp: bam.NewBaseApp("mock", cdc, logger, db), + BaseApp: bam.NewBaseApp("mock", logger, db, auth.DefaultTxDecoder(cdc)), Cdc: cdc, KeyMain: sdk.NewKVStoreKey("main"), KeyAccount: sdk.NewKVStoreKey("acc"), diff --git a/x/stake/tags/tags.go b/x/stake/tags/tags.go index edb4eda07..8ef60aa84 100644 --- a/x/stake/tags/tags.go +++ b/x/stake/tags/tags.go @@ -2,7 +2,7 @@ package tags import ( - "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) var ( @@ -14,10 +14,10 @@ var ( ActionBeginRedelegation = []byte("begin-redelegation") ActionCompleteRedelegation = []byte("complete-redelegation") - Action = types.TagAction - SrcValidator = types.TagSrcValidator - DstValidator = types.TagDstValidator - Delegator = types.TagDelegator + Action = sdk.TagAction + SrcValidator = sdk.TagSrcValidator + DstValidator = sdk.TagDstValidator + Delegator = sdk.TagDelegator Moniker = "moniker" - Identity = "Identity" + Identity = "identity" )