Merge branch 'develop' into rigel/no-endblock-rat-calcs

This commit is contained in:
Rigel 2018-07-23 14:59:06 -04:00 committed by GitHub
commit 52916f3c25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 628 additions and 291 deletions

View File

@ -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))

View File

@ -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

1
Gopkg.lock generated
View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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{})

View File

@ -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)

View File

@ -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
}

View File

@ -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{

View File

@ -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
}

View File

@ -112,6 +112,7 @@ func main() {
client.GetCommands(
govcmd.GetCmdQueryProposal("gov", cdc),
govcmd.GetCmdQueryVote("gov", cdc),
govcmd.GetCmdQueryVotes("gov", cdc),
)...)
govCmd.AddCommand(
client.PostCommands(

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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,

View File

@ -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 {

View File

@ -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.

View File

@ -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")

View File

@ -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")

View File

@ -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"),

View File

@ -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"),

View File

@ -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))

View File

@ -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.

View File

@ -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...
}
}

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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()

22
x/gov/tags/tags.go Normal file
View File

@ -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"
)

View File

@ -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"),

View File

@ -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"
)