Merge develop
This commit is contained in:
commit
60fc7c7919
|
@ -162,6 +162,24 @@ jobs:
|
||||||
export PATH="$GOBIN:$PATH"
|
export PATH="$GOBIN:$PATH"
|
||||||
make test_sim_gaia_import_export
|
make test_sim_gaia_import_export
|
||||||
|
|
||||||
|
test_sim_gaia_simulation_after_import:
|
||||||
|
<<: *defaults
|
||||||
|
parallelism: 1
|
||||||
|
steps:
|
||||||
|
- attach_workspace:
|
||||||
|
at: /tmp/workspace
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: dependencies
|
||||||
|
command: |
|
||||||
|
export PATH="$GOBIN:$PATH"
|
||||||
|
make get_vendor_deps
|
||||||
|
- run:
|
||||||
|
name: Test Gaia import/export simulation
|
||||||
|
command: |
|
||||||
|
export PATH="$GOBIN:$PATH"
|
||||||
|
make test_sim_gaia_simulation_after_import
|
||||||
|
|
||||||
test_sim_gaia_multi_seed:
|
test_sim_gaia_multi_seed:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
parallelism: 1
|
parallelism: 1
|
||||||
|
@ -301,6 +319,9 @@ workflows:
|
||||||
- test_sim_gaia_import_export:
|
- test_sim_gaia_import_export:
|
||||||
requires:
|
requires:
|
||||||
- setup_dependencies
|
- setup_dependencies
|
||||||
|
- test_sim_gaia_simulation_after_import:
|
||||||
|
requires:
|
||||||
|
- setup_dependencies
|
||||||
- test_sim_gaia_multi_seed:
|
- test_sim_gaia_multi_seed:
|
||||||
requires:
|
requires:
|
||||||
- setup_dependencies
|
- setup_dependencies
|
||||||
|
|
|
@ -643,6 +643,7 @@
|
||||||
"github.com/bgentry/speakeasy",
|
"github.com/bgentry/speakeasy",
|
||||||
"github.com/btcsuite/btcd/btcec",
|
"github.com/btcsuite/btcd/btcec",
|
||||||
"github.com/cosmos/go-bip39",
|
"github.com/cosmos/go-bip39",
|
||||||
|
"github.com/gogo/protobuf/proto",
|
||||||
"github.com/golang/protobuf/proto",
|
"github.com/golang/protobuf/proto",
|
||||||
"github.com/gorilla/mux",
|
"github.com/gorilla/mux",
|
||||||
"github.com/mattn/go-isatty",
|
"github.com/mattn/go-isatty",
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -184,6 +184,10 @@ test_sim_gaia_import_export:
|
||||||
@echo "Running Gaia import/export simulation. This may take several minutes..."
|
@echo "Running Gaia import/export simulation. This may take several minutes..."
|
||||||
@bash scripts/import-export-sim.sh 50
|
@bash scripts/import-export-sim.sh 50
|
||||||
|
|
||||||
|
test_sim_gaia_simulation_after_import:
|
||||||
|
@echo "Running Gaia simulation-after-import. This may take several minutes..."
|
||||||
|
@bash scripts/simulation-after-import.sh 50
|
||||||
|
|
||||||
test_sim_gaia_multi_seed:
|
test_sim_gaia_multi_seed:
|
||||||
@echo "Running multi-seed Gaia simulation. This may take awhile!"
|
@echo "Running multi-seed Gaia simulation. This may take awhile!"
|
||||||
@bash scripts/multisim.sh 25
|
@bash scripts/multisim.sh 25
|
||||||
|
|
31
PENDING.md
31
PENDING.md
|
@ -11,13 +11,18 @@ BREAKING CHANGES
|
||||||
* [cli] [\#2786](https://github.com/cosmos/cosmos-sdk/pull/2786) Fix redelegation command flow
|
* [cli] [\#2786](https://github.com/cosmos/cosmos-sdk/pull/2786) Fix redelegation command flow
|
||||||
* [cli] [\#2829](https://github.com/cosmos/cosmos-sdk/pull/2829) add-genesis-account command now validates state when adding accounts
|
* [cli] [\#2829](https://github.com/cosmos/cosmos-sdk/pull/2829) add-genesis-account command now validates state when adding accounts
|
||||||
* [cli] [\#2804](https://github.com/cosmos/cosmos-sdk/issues/2804) Check whether key exists before passing it on to `tx create-validator`.
|
* [cli] [\#2804](https://github.com/cosmos/cosmos-sdk/issues/2804) Check whether key exists before passing it on to `tx create-validator`.
|
||||||
|
* [cli] [\#2874](https://github.com/cosmos/cosmos-sdk/pull/2874) `gaiacli tx sign` takes an optional `--output-document` flag to support output redirection.
|
||||||
|
* [cli] [\#2875](https://github.com/cosmos/cosmos-sdk/pull/2875) Refactor `gaiad gentx` and avoid redirection to `gaiacli tx sign` for tx signing.
|
||||||
|
|
||||||
* Gaia
|
* Gaia
|
||||||
|
* [mint] [\#2825] minting now occurs every block, inflation parameter updates still hourly
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
* [\#2752](https://github.com/cosmos/cosmos-sdk/pull/2752) Don't hardcode bondable denom.
|
* [\#2752](https://github.com/cosmos/cosmos-sdk/pull/2752) Don't hardcode bondable denom.
|
||||||
|
* [\#2701](https://github.com/cosmos/cosmos-sdk/issues/2701) Account numbers and sequence numbers in `auth` are now `uint64` instead of `int64`
|
||||||
* [\#2019](https://github.com/cosmos/cosmos-sdk/issues/2019) Cap total number of signatures. Current per-transaction limit is 7, and if that is exceeded transaction is rejected.
|
* [\#2019](https://github.com/cosmos/cosmos-sdk/issues/2019) Cap total number of signatures. Current per-transaction limit is 7, and if that is exceeded transaction is rejected.
|
||||||
* [\#2801](https://github.com/cosmos/cosmos-sdk/pull/2801) Remove AppInit structure.
|
* [\#2801](https://github.com/cosmos/cosmos-sdk/pull/2801) Remove AppInit structure.
|
||||||
|
* [\#2798](https://github.com/cosmos/cosmos-sdk/issues/2798) Governance API has miss-spelled English word in JSON response ('depositer' -> 'depositor')
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
|
|
||||||
|
@ -32,6 +37,7 @@ FEATURES
|
||||||
* [gov][cli] [\#2479](https://github.com/cosmos/cosmos-sdk/issues/2479) Added governance
|
* [gov][cli] [\#2479](https://github.com/cosmos/cosmos-sdk/issues/2479) Added governance
|
||||||
parameter query commands.
|
parameter query commands.
|
||||||
* [stake][cli] [\#2027] Add CLI query command for getting all delegations to a specific validator.
|
* [stake][cli] [\#2027] Add CLI query command for getting all delegations to a specific validator.
|
||||||
|
* [\#2840](https://github.com/cosmos/cosmos-sdk/pull/2840) Standardize CLI exports from modules
|
||||||
|
|
||||||
* Gaia
|
* Gaia
|
||||||
* [app] \#2791 Support export at a specific height, with `gaiad export --height=HEIGHT`.
|
* [app] \#2791 Support export at a specific height, with `gaiad export --height=HEIGHT`.
|
||||||
|
@ -39,9 +45,11 @@ FEATURES
|
||||||
for getting governance parameters.
|
for getting governance parameters.
|
||||||
* [app] \#2663 - Runtime-assertable invariants
|
* [app] \#2663 - Runtime-assertable invariants
|
||||||
* [app] \#2791 Support export at a specific height, with `gaiad export --height=HEIGHT`.
|
* [app] \#2791 Support export at a specific height, with `gaiad export --height=HEIGHT`.
|
||||||
|
* [app] \#2812 Support export alterations to prepare for restarting at zero-height
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
* [simulator] \#2682 MsgEditValidator now looks at the validator's max rate, thus it now succeeds a significant portion of the time
|
* [simulator] \#2682 MsgEditValidator now looks at the validator's max rate, thus it now succeeds a significant portion of the time
|
||||||
|
* [core] \#2775 Add deliverTx maximum block gas limit
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
|
|
||||||
|
@ -50,16 +58,27 @@ IMPROVEMENTS
|
||||||
|
|
||||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||||
* [gaia-lite] [\#2819](https://github.com/cosmos/cosmos-sdk/pull/2819) Tx search now supports multiple tags as query parameters
|
* [gaia-lite] [\#2819](https://github.com/cosmos/cosmos-sdk/pull/2819) Tx search now supports multiple tags as query parameters
|
||||||
|
* [\#2836](https://github.com/cosmos/cosmos-sdk/pull/2836) Expose LCD router to allow users to register routes there.
|
||||||
|
|
||||||
* Gaia CLI (`gaiacli`)
|
* Gaia CLI (`gaiacli`)
|
||||||
* [\#2749](https://github.com/cosmos/cosmos-sdk/pull/2749) Add --chain-id flag to gaiad testnet
|
* [\#2749](https://github.com/cosmos/cosmos-sdk/pull/2749) Add --chain-id flag to gaiad testnet
|
||||||
|
|
||||||
* Gaia
|
* Gaia
|
||||||
- #2773 Require moniker to be provided on `gaiad init`.
|
- #2772 Update BaseApp to not persist state when the ante handler fails on DeliverTx.
|
||||||
- #2672 [Makefile] Updated for better Windows compatibility and ledger support logic, get_tools was rewritten as a cross-compatible Makefile.
|
- #2773 Require moniker to be provided on `gaiad init`.
|
||||||
- [#110](https://github.com/tendermint/devops/issues/110) Updated CircleCI job to trigger website build when cosmos docs are updated.
|
- #2672 [Makefile] Updated for better Windows compatibility and ledger support logic, get_tools was rewritten as a cross-compatible Makefile.
|
||||||
|
- [#110](https://github.com/tendermint/devops/issues/110) Updated CircleCI job to trigger website build when cosmos docs are updated.
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
- [x/mock/simulation] [\#2720] major cleanup, introduction of helper objects, reorganization
|
- [x/mock/simulation] [\#2720] major cleanup, introduction of helper objects, reorganization
|
||||||
|
- \#2821 Codespaces are now strings
|
||||||
|
- [types] #2776 Improve safety of `Coin` and `Coins` types. Various functions
|
||||||
|
and methods will panic when a negative amount is discovered.
|
||||||
|
- #2815 Gas unit fields changed from `int64` to `uint64`.
|
||||||
|
- #2821 Codespaces are now strings
|
||||||
|
- #2779 Introduce `ValidateBasic` to the `Tx` interface and call it in the ante
|
||||||
|
handler.
|
||||||
|
- #2825 More staking and distribution invariants
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
- #2796 Update to go-amino 0.14.1
|
- #2796 Update to go-amino 0.14.1
|
||||||
|
@ -68,16 +87,20 @@ IMPROVEMENTS
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
|
||||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||||
|
- [gaia-lite] #2868 Added handler for governance tally endpoit
|
||||||
|
|
||||||
* Gaia CLI (`gaiacli`)
|
* Gaia CLI (`gaiacli`)
|
||||||
|
|
||||||
* Gaia
|
* Gaia
|
||||||
* [\#2723] Use `cosmosvalcons` Bech32 prefix in `tendermint show-address`
|
* [\#2723] Use `cosmosvalcons` Bech32 prefix in `tendermint show-address`
|
||||||
* [\#2742](https://github.com/cosmos/cosmos-sdk/issues/2742) Fix time format of TimeoutCommit override
|
* [\#2742](https://github.com/cosmos/cosmos-sdk/issues/2742) Fix time format of TimeoutCommit override
|
||||||
|
* [\#2898](https://github.com/cosmos/cosmos-sdk/issues/2898) Remove redundant '$' in docker-compose.yml
|
||||||
|
|
||||||
* SDK
|
* SDK
|
||||||
|
|
||||||
- \#2733 [x/gov, x/mock/simulation] Fix governance simulation, update x/gov import/export
|
- \#2733 [x/gov, x/mock/simulation] Fix governance simulation, update x/gov import/export
|
||||||
|
- \#2854 [x/bank] Remove unused bank.MsgIssue, prevent possible panic
|
||||||
|
- \#2884 [docs/examples] Fix `basecli version` panic
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
* [\#2797](https://github.com/tendermint/tendermint/pull/2797) AddressBook requires addresses to have IDs; Do not crap out immediately after sending pex addrs in seed mode
|
* [\#2797](https://github.com/tendermint/tendermint/pull/2797) AddressBook requires addresses to have IDs; Do not crap out immediately after sending pex addrs in seed mode
|
||||||
|
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
|
|
||||||
|
@ -20,11 +20,8 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/version"
|
"github.com/cosmos/cosmos-sdk/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Key to store the header in the DB itself.
|
// Key to store the consensus params in the main store.
|
||||||
// Use the db directly instead of a store to avoid
|
var mainConsensusParamsKey = []byte("consensus_params")
|
||||||
// conflicts with handlers writing to the store
|
|
||||||
// and to avoid affecting the Merkle root.
|
|
||||||
var dbHeaderKey = []byte("header")
|
|
||||||
|
|
||||||
// Enum mode for app.runTx
|
// Enum mode for app.runTx
|
||||||
type runTxMode uint8
|
type runTxMode uint8
|
||||||
|
@ -47,12 +44,13 @@ type BaseApp struct {
|
||||||
cms sdk.CommitMultiStore // Main (uncached) state
|
cms sdk.CommitMultiStore // Main (uncached) state
|
||||||
router Router // handle any kind of message
|
router Router // handle any kind of message
|
||||||
queryRouter QueryRouter // router for redirecting query calls
|
queryRouter QueryRouter // router for redirecting query calls
|
||||||
codespacer *sdk.Codespacer // handle module codespacing
|
|
||||||
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
|
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
|
||||||
|
|
||||||
anteHandler sdk.AnteHandler // ante handler for fee and auth
|
// set upon LoadVersion or LoadLatestVersion.
|
||||||
|
mainKey *sdk.KVStoreKey // Main KVStore in cms
|
||||||
|
|
||||||
// may be nil
|
// may be nil
|
||||||
|
anteHandler sdk.AnteHandler // ante handler for fee and auth
|
||||||
initChainer sdk.InitChainer // initialize state with validators and state blob
|
initChainer sdk.InitChainer // initialize state with validators and state blob
|
||||||
beginBlocker sdk.BeginBlocker // logic to run before any txs
|
beginBlocker sdk.BeginBlocker // logic to run before any txs
|
||||||
endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes
|
endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes
|
||||||
|
@ -68,7 +66,11 @@ type BaseApp struct {
|
||||||
deliverState *state // for DeliverTx
|
deliverState *state // for DeliverTx
|
||||||
voteInfos []abci.VoteInfo // absent validators from begin block
|
voteInfos []abci.VoteInfo // absent validators from begin block
|
||||||
|
|
||||||
// minimum fees for spam prevention
|
// consensus params
|
||||||
|
// TODO move this in the future to baseapp param store on main store.
|
||||||
|
consensusParams *abci.ConsensusParams
|
||||||
|
|
||||||
|
// spam prevention
|
||||||
minimumFees sdk.Coins
|
minimumFees sdk.Coins
|
||||||
|
|
||||||
// flag for sealing
|
// flag for sealing
|
||||||
|
@ -79,10 +81,6 @@ var _ abci.Application = (*BaseApp)(nil)
|
||||||
|
|
||||||
// NewBaseApp returns a reference to an initialized BaseApp.
|
// NewBaseApp returns a reference to an initialized BaseApp.
|
||||||
//
|
//
|
||||||
// TODO: Determine how to use a flexible and robust configuration paradigm that
|
|
||||||
// allows for sensible defaults while being highly configurable
|
|
||||||
// (e.g. functional options).
|
|
||||||
//
|
|
||||||
// NOTE: The db is used to store the version number for now.
|
// NOTE: The db is used to store the version number for now.
|
||||||
// Accepts a user-defined txDecoder
|
// Accepts a user-defined txDecoder
|
||||||
// Accepts variable number of option functions, which act on the BaseApp to set configuration choices
|
// Accepts variable number of option functions, which act on the BaseApp to set configuration choices
|
||||||
|
@ -94,13 +92,8 @@ func NewBaseApp(name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecod
|
||||||
cms: store.NewCommitMultiStore(db),
|
cms: store.NewCommitMultiStore(db),
|
||||||
router: NewRouter(),
|
router: NewRouter(),
|
||||||
queryRouter: NewQueryRouter(),
|
queryRouter: NewQueryRouter(),
|
||||||
codespacer: sdk.NewCodespacer(),
|
|
||||||
txDecoder: txDecoder,
|
txDecoder: txDecoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the undefined & root codespaces, which should not be used by
|
|
||||||
// any modules.
|
|
||||||
app.codespacer.RegisterOrPanic(sdk.CodespaceRoot)
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
option(app)
|
option(app)
|
||||||
}
|
}
|
||||||
|
@ -118,11 +111,6 @@ func (app *BaseApp) SetCommitMultiStoreTracer(w io.Writer) {
|
||||||
app.cms.WithTracer(w)
|
app.cms.WithTracer(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the next available codespace through the baseapp's codespacer, starting from a default
|
|
||||||
func (app *BaseApp) RegisterCodespace(codespace sdk.CodespaceType) sdk.CodespaceType {
|
|
||||||
return app.codespacer.RegisterNext(codespace)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mount IAVL stores to the provided keys in the BaseApp multistore
|
// Mount IAVL stores to the provided keys in the BaseApp multistore
|
||||||
func (app *BaseApp) MountStoresIAVL(keys ...*sdk.KVStoreKey) {
|
func (app *BaseApp) MountStoresIAVL(keys ...*sdk.KVStoreKey) {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
|
@ -148,21 +136,23 @@ func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// load latest application version
|
// load latest application version
|
||||||
func (app *BaseApp) LoadLatestVersion(mainKey sdk.StoreKey) error {
|
// panics if called more than once on a running baseapp
|
||||||
|
func (app *BaseApp) LoadLatestVersion(mainKey *sdk.KVStoreKey) error {
|
||||||
err := app.cms.LoadLatestVersion()
|
err := app.cms.LoadLatestVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return app.initFromStore(mainKey)
|
return app.initFromMainStore(mainKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// load application version
|
// load application version
|
||||||
func (app *BaseApp) LoadVersion(version int64, mainKey sdk.StoreKey) error {
|
// panics if called more than once on a running baseapp
|
||||||
|
func (app *BaseApp) LoadVersion(version int64, mainKey *sdk.KVStoreKey) error {
|
||||||
err := app.cms.LoadVersion(version)
|
err := app.cms.LoadVersion(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return app.initFromStore(mainKey)
|
return app.initFromMainStore(mainKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// the last CommitID of the multistore
|
// the last CommitID of the multistore
|
||||||
|
@ -176,13 +166,34 @@ func (app *BaseApp) LastBlockHeight() int64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializes the remaining logic from app.cms
|
// initializes the remaining logic from app.cms
|
||||||
func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error {
|
func (app *BaseApp) initFromMainStore(mainKey *sdk.KVStoreKey) error {
|
||||||
|
|
||||||
// main store should exist.
|
// main store should exist.
|
||||||
// TODO: we don't actually need the main store here
|
mainStore := app.cms.GetKVStore(mainKey)
|
||||||
main := app.cms.GetKVStore(mainKey)
|
if mainStore == nil {
|
||||||
if main == nil {
|
|
||||||
return errors.New("baseapp expects MultiStore with 'main' KVStore")
|
return errors.New("baseapp expects MultiStore with 'main' KVStore")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// memoize mainKey
|
||||||
|
if app.mainKey != nil {
|
||||||
|
panic("app.mainKey expected to be nil; duplicate init?")
|
||||||
|
}
|
||||||
|
app.mainKey = mainKey
|
||||||
|
|
||||||
|
// load consensus params from the main store
|
||||||
|
consensusParamsBz := mainStore.Get(mainConsensusParamsKey)
|
||||||
|
if consensusParamsBz != nil {
|
||||||
|
var consensusParams = &abci.ConsensusParams{}
|
||||||
|
err := proto.Unmarshal(consensusParamsBz, consensusParams)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
app.setConsensusParams(consensusParams)
|
||||||
|
} else {
|
||||||
|
// It will get saved later during InitChain.
|
||||||
|
// TODO assert that InitChain hasn't yet been called.
|
||||||
|
}
|
||||||
|
|
||||||
// Needed for `gaiad export`, which inits from store but never calls initchain
|
// Needed for `gaiad export`, which inits from store but never calls initchain
|
||||||
app.setCheckState(abci.Header{})
|
app.setCheckState(abci.Header{})
|
||||||
|
|
||||||
|
@ -211,6 +222,10 @@ func (st *state) CacheMultiStore() sdk.CacheMultiStore {
|
||||||
return st.ms.CacheMultiStore()
|
return st.ms.CacheMultiStore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (st *state) Context() sdk.Context {
|
||||||
|
return st.ctx
|
||||||
|
}
|
||||||
|
|
||||||
func (app *BaseApp) setCheckState(header abci.Header) {
|
func (app *BaseApp) setCheckState(header abci.Header) {
|
||||||
ms := app.cms.CacheMultiStore()
|
ms := app.cms.CacheMultiStore()
|
||||||
app.checkState = &state{
|
app.checkState = &state{
|
||||||
|
@ -227,6 +242,29 @@ func (app *BaseApp) setDeliverState(header abci.Header) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setConsensusParams memoizes the consensus params.
|
||||||
|
func (app *BaseApp) setConsensusParams(consensusParams *abci.ConsensusParams) {
|
||||||
|
app.consensusParams = consensusParams
|
||||||
|
}
|
||||||
|
|
||||||
|
// setConsensusParams stores the consensus params to the main store.
|
||||||
|
func (app *BaseApp) storeConsensusParams(consensusParams *abci.ConsensusParams) {
|
||||||
|
consensusParamsBz, err := proto.Marshal(consensusParams)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
mainStore := app.cms.GetKVStore(app.mainKey)
|
||||||
|
mainStore.Set(mainConsensusParamsKey, consensusParamsBz)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getMaximumBlockGas gets the maximum gas from the consensus params.
|
||||||
|
func (app *BaseApp) getMaximumBlockGas() (maxGas uint64) {
|
||||||
|
if app.consensusParams == nil || app.consensusParams.BlockSize == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uint64(app.consensusParams.BlockSize.MaxGas)
|
||||||
|
}
|
||||||
|
|
||||||
//______________________________________________________________________________
|
//______________________________________________________________________________
|
||||||
|
|
||||||
// ABCI
|
// ABCI
|
||||||
|
@ -249,8 +287,15 @@ func (app *BaseApp) SetOption(req abci.RequestSetOption) (res abci.ResponseSetOp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements ABCI
|
// Implements ABCI
|
||||||
// InitChain runs the initialization logic directly on the CommitMultiStore and commits it.
|
// InitChain runs the initialization logic directly on the CommitMultiStore.
|
||||||
func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain) {
|
func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain) {
|
||||||
|
|
||||||
|
// Stash the consensus params in the cms main store and memoize.
|
||||||
|
if req.ConsensusParams != nil {
|
||||||
|
app.setConsensusParams(req.ConsensusParams)
|
||||||
|
app.storeConsensusParams(req.ConsensusParams)
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the deliver state and check state with ChainID and run initChain
|
// Initialize the deliver state and check state with ChainID and run initChain
|
||||||
app.setDeliverState(abci.Header{ChainID: req.ChainId})
|
app.setDeliverState(abci.Header{ChainID: req.ChainId})
|
||||||
app.setCheckState(abci.Header{ChainID: req.ChainId})
|
app.setCheckState(abci.Header{ChainID: req.ChainId})
|
||||||
|
@ -258,6 +303,11 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC
|
||||||
if app.initChainer == nil {
|
if app.initChainer == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add block gas meter for any genesis transactions (allow infinite gas)
|
||||||
|
app.deliverState.ctx = app.deliverState.ctx.
|
||||||
|
WithBlockGasMeter(sdk.NewInfiniteGasMeter())
|
||||||
|
|
||||||
res = app.initChainer(app.deliverState.ctx, req)
|
res = app.initChainer(app.deliverState.ctx, req)
|
||||||
|
|
||||||
// NOTE: we don't commit, but BeginBlock for block 1
|
// NOTE: we don't commit, but BeginBlock for block 1
|
||||||
|
@ -329,8 +379,9 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc
|
||||||
}
|
}
|
||||||
case "version":
|
case "version":
|
||||||
return abci.ResponseQuery{
|
return abci.ResponseQuery{
|
||||||
Code: uint32(sdk.ABCICodeOK),
|
Code: uint32(sdk.CodeOK),
|
||||||
Value: []byte(version.GetVersion()),
|
Codespace: string(sdk.CodespaceRoot),
|
||||||
|
Value: []byte(version.GetVersion()),
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
result = sdk.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path)).Result()
|
result = sdk.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path)).Result()
|
||||||
|
@ -339,8 +390,9 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc
|
||||||
// Encode with json
|
// Encode with json
|
||||||
value := codec.Cdc.MustMarshalBinaryLengthPrefixed(result)
|
value := codec.Cdc.MustMarshalBinaryLengthPrefixed(result)
|
||||||
return abci.ResponseQuery{
|
return abci.ResponseQuery{
|
||||||
Code: uint32(sdk.ABCICodeOK),
|
Code: uint32(sdk.CodeOK),
|
||||||
Value: value,
|
Codespace: string(sdk.CodespaceRoot),
|
||||||
|
Value: value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg := "Expected second parameter to be either simulate or version, neither was present"
|
msg := "Expected second parameter to be either simulate or version, neither was present"
|
||||||
|
@ -392,6 +444,7 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
|
||||||
return sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult()
|
return sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache wrap the commit-multistore for safety.
|
||||||
ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger).
|
ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger).
|
||||||
WithMinimumFees(app.minimumFees)
|
WithMinimumFees(app.minimumFees)
|
||||||
|
|
||||||
|
@ -400,12 +453,13 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
|
||||||
resBytes, err := querier(ctx, path[2:], req)
|
resBytes, err := querier(ctx, path[2:], req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return abci.ResponseQuery{
|
return abci.ResponseQuery{
|
||||||
Code: uint32(err.ABCICode()),
|
Code: uint32(err.Code()),
|
||||||
Log: err.ABCILog(),
|
Codespace: string(err.Codespace()),
|
||||||
|
Log: err.ABCILog(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return abci.ResponseQuery{
|
return abci.ResponseQuery{
|
||||||
Code: uint32(sdk.ABCICodeOK),
|
Code: uint32(sdk.CodeOK),
|
||||||
Value: resBytes,
|
Value: resBytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,9 +481,20 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
||||||
} else {
|
} else {
|
||||||
// In the first block, app.deliverState.ctx will already be initialized
|
// In the first block, app.deliverState.ctx will already be initialized
|
||||||
// by InitChain. Context is now updated with Header information.
|
// by InitChain. Context is now updated with Header information.
|
||||||
app.deliverState.ctx = app.deliverState.ctx.WithBlockHeader(req.Header).WithBlockHeight(req.Header.Height)
|
app.deliverState.ctx = app.deliverState.ctx.
|
||||||
|
WithBlockHeader(req.Header).
|
||||||
|
WithBlockHeight(req.Header.Height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add block gas meter
|
||||||
|
var gasMeter sdk.GasMeter
|
||||||
|
if maxGas := app.getMaximumBlockGas(); maxGas > 0 {
|
||||||
|
gasMeter = sdk.NewGasMeter(maxGas)
|
||||||
|
} else {
|
||||||
|
gasMeter = sdk.NewInfiniteGasMeter()
|
||||||
|
}
|
||||||
|
app.deliverState.ctx = app.deliverState.ctx.WithBlockGasMeter(gasMeter)
|
||||||
|
|
||||||
if app.beginBlocker != nil {
|
if app.beginBlocker != nil {
|
||||||
res = app.beginBlocker(app.deliverState.ctx, req)
|
res = app.beginBlocker(app.deliverState.ctx, req)
|
||||||
}
|
}
|
||||||
|
@ -459,17 +524,18 @@ func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) {
|
||||||
Code: uint32(result.Code),
|
Code: uint32(result.Code),
|
||||||
Data: result.Data,
|
Data: result.Data,
|
||||||
Log: result.Log,
|
Log: result.Log,
|
||||||
GasWanted: result.GasWanted,
|
GasWanted: int64(result.GasWanted), // TODO: Should type accept unsigned ints?
|
||||||
GasUsed: result.GasUsed,
|
GasUsed: int64(result.GasUsed), // TODO: Should type accept unsigned ints?
|
||||||
Tags: result.Tags,
|
Tags: result.Tags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements ABCI
|
// Implements ABCI
|
||||||
func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
|
func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
|
||||||
|
|
||||||
// Decode the Tx.
|
// Decode the Tx.
|
||||||
var result sdk.Result
|
|
||||||
var tx, err = app.txDecoder(txBytes)
|
var tx, err = app.txDecoder(txBytes)
|
||||||
|
var result sdk.Result
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result = err.Result()
|
result = err.Result()
|
||||||
} else {
|
} else {
|
||||||
|
@ -482,10 +548,11 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
|
||||||
// Tell the blockchain engine (i.e. Tendermint).
|
// Tell the blockchain engine (i.e. Tendermint).
|
||||||
return abci.ResponseDeliverTx{
|
return abci.ResponseDeliverTx{
|
||||||
Code: uint32(result.Code),
|
Code: uint32(result.Code),
|
||||||
|
Codespace: string(result.Codespace),
|
||||||
Data: result.Data,
|
Data: result.Data,
|
||||||
Log: result.Log,
|
Log: result.Log,
|
||||||
GasWanted: result.GasWanted,
|
GasWanted: int64(result.GasWanted), // TODO: Should type accept unsigned ints?
|
||||||
GasUsed: result.GasUsed,
|
GasUsed: int64(result.GasUsed), // TODO: Should type accept unsigned ints?
|
||||||
Tags: result.Tags,
|
Tags: result.Tags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,7 +568,6 @@ func validateBasicTxMsgs(msgs []sdk.Msg) sdk.Error {
|
||||||
// Validate the Msg.
|
// Validate the Msg.
|
||||||
err := msg.ValidateBasic()
|
err := msg.ValidateBasic()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = err.WithDefaultCodespace(sdk.CodespaceRoot)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,13 +575,13 @@ func validateBasicTxMsgs(msgs []sdk.Msg) sdk.Error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve the context for the ante handler and store the tx bytes; store
|
// retrieve the context for the tx w/ txBytes and other memoized values.
|
||||||
// the vote infos if the tx runs within the deliverTx() state.
|
func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) (ctx sdk.Context) {
|
||||||
func (app *BaseApp) getContextForAnte(mode runTxMode, txBytes []byte) (ctx sdk.Context) {
|
ctx = app.getState(mode).ctx.
|
||||||
// Get the context
|
WithTxBytes(txBytes).
|
||||||
ctx = getState(app, mode).ctx.WithTxBytes(txBytes)
|
WithVoteInfos(app.voteInfos)
|
||||||
if mode == runTxModeDeliver {
|
if mode == runTxModeSimulate {
|
||||||
ctx = ctx.WithVoteInfos(app.voteInfos)
|
ctx, _ = ctx.CacheContext()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -526,7 +592,8 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
||||||
logs := make([]string, 0, len(msgs))
|
logs := make([]string, 0, len(msgs))
|
||||||
var data []byte // NOTE: we just append them all (?!)
|
var data []byte // NOTE: we just append them all (?!)
|
||||||
var tags sdk.Tags // also just append them all
|
var tags sdk.Tags // also just append them all
|
||||||
var code sdk.ABCICodeType
|
var code sdk.CodeType
|
||||||
|
var codespace sdk.CodespaceType
|
||||||
for msgIdx, msg := range msgs {
|
for msgIdx, msg := range msgs {
|
||||||
// Match route.
|
// Match route.
|
||||||
msgRoute := msg.Route()
|
msgRoute := msg.Route()
|
||||||
|
@ -553,6 +620,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
||||||
if !msgResult.IsOK() {
|
if !msgResult.IsOK() {
|
||||||
logs = append(logs, fmt.Sprintf("Msg %d failed: %s", msgIdx, msgResult.Log))
|
logs = append(logs, fmt.Sprintf("Msg %d failed: %s", msgIdx, msgResult.Log))
|
||||||
code = msgResult.Code
|
code = msgResult.Code
|
||||||
|
codespace = msgResult.Codespace
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,10 +630,11 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
||||||
|
|
||||||
// Set the final gas values.
|
// Set the final gas values.
|
||||||
result = sdk.Result{
|
result = sdk.Result{
|
||||||
Code: code,
|
Code: code,
|
||||||
Data: data,
|
Codespace: codespace,
|
||||||
Log: strings.Join(logs, "\n"),
|
Data: data,
|
||||||
GasUsed: ctx.GasMeter().GasConsumed(),
|
Log: strings.Join(logs, "\n"),
|
||||||
|
GasUsed: ctx.GasMeter().GasConsumed(),
|
||||||
// TODO: FeeAmount/FeeDenom
|
// TODO: FeeAmount/FeeDenom
|
||||||
Tags: tags,
|
Tags: tags,
|
||||||
}
|
}
|
||||||
|
@ -575,7 +644,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
||||||
|
|
||||||
// Returns the applicantion's deliverState if app is in runTxModeDeliver,
|
// Returns the applicantion's deliverState if app is in runTxModeDeliver,
|
||||||
// otherwise it returns the application's checkstate.
|
// otherwise it returns the application's checkstate.
|
||||||
func getState(app *BaseApp, mode runTxMode) *state {
|
func (app *BaseApp) getState(mode runTxMode) *state {
|
||||||
if mode == runTxModeCheck || mode == runTxModeSimulate {
|
if mode == runTxModeCheck || mode == runTxModeSimulate {
|
||||||
return app.checkState
|
return app.checkState
|
||||||
}
|
}
|
||||||
|
@ -583,24 +652,45 @@ func getState(app *BaseApp, mode runTxMode) *state {
|
||||||
return app.deliverState
|
return app.deliverState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *BaseApp) initializeContext(ctx sdk.Context, mode runTxMode) sdk.Context {
|
// cacheTxContext returns a new context based off of the provided context with
|
||||||
if mode == runTxModeSimulate {
|
// a cache wrapped multi-store.
|
||||||
ctx = ctx.WithMultiStore(getState(app, runTxModeSimulate).CacheMultiStore())
|
func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (
|
||||||
|
sdk.Context, sdk.CacheMultiStore) {
|
||||||
|
|
||||||
|
ms := ctx.MultiStore()
|
||||||
|
// TODO: https://github.com/cosmos/cosmos-sdk/issues/2824
|
||||||
|
msCache := ms.CacheMultiStore()
|
||||||
|
if msCache.TracingEnabled() {
|
||||||
|
msCache = msCache.WithTracingContext(
|
||||||
|
sdk.TraceContext(
|
||||||
|
map[string]interface{}{
|
||||||
|
"txHash": fmt.Sprintf("%X", tmhash.Sum(txBytes)),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).(sdk.CacheMultiStore)
|
||||||
}
|
}
|
||||||
return ctx
|
|
||||||
|
return ctx.WithMultiStore(msCache), msCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// runTx processes a transaction. The transactions is proccessed via an
|
// runTx processes a transaction. The transactions is proccessed via an
|
||||||
// anteHandler. txBytes may be nil in some cases, eg. in tests. Also, in the
|
// anteHandler. The provided txBytes may be nil in some cases, eg. in tests. For
|
||||||
// future we may support "internal" transactions.
|
// further details on transaction execution, reference the BaseApp SDK
|
||||||
|
// documentation.
|
||||||
func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk.Result) {
|
func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk.Result) {
|
||||||
// NOTE: GasWanted should be returned by the AnteHandler. GasUsed is
|
// NOTE: GasWanted should be returned by the AnteHandler. GasUsed is
|
||||||
// determined by the GasMeter. We need access to the context to get the gas
|
// determined by the GasMeter. We need access to the context to get the gas
|
||||||
// meter so we initialize upfront.
|
// meter so we initialize upfront.
|
||||||
var gasWanted int64
|
var gasWanted uint64
|
||||||
var msCache sdk.CacheMultiStore
|
|
||||||
ctx := app.getContextForAnte(mode, txBytes)
|
ctx := app.getContextForTx(mode, txBytes)
|
||||||
ctx = app.initializeContext(ctx, mode)
|
ms := ctx.MultiStore()
|
||||||
|
|
||||||
|
// only run the tx if there is block gas remaining
|
||||||
|
if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() {
|
||||||
|
result = sdk.ErrOutOfGas("no block gas left to run tx").Result()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -618,43 +708,65 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk
|
||||||
result.GasUsed = ctx.GasMeter().GasConsumed()
|
result.GasUsed = ctx.GasMeter().GasConsumed()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// If BlockGasMeter() panics it will be caught by the above recover and
|
||||||
|
// return an error - in any case BlockGasMeter will consume gas past
|
||||||
|
// the limit.
|
||||||
|
// NOTE: this must exist in a separate defer function for the
|
||||||
|
// above recovery to recover from this one
|
||||||
|
defer func() {
|
||||||
|
if mode == runTxModeDeliver {
|
||||||
|
ctx.BlockGasMeter().ConsumeGas(
|
||||||
|
ctx.GasMeter().GasConsumedToLimit(), "block gas meter")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
var msgs = tx.GetMsgs()
|
var msgs = tx.GetMsgs()
|
||||||
if err := validateBasicTxMsgs(msgs); err != nil {
|
if err := validateBasicTxMsgs(msgs); err != nil {
|
||||||
return err.Result()
|
return err.Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the ante handler
|
// Execute the ante handler if one is defined.
|
||||||
if app.anteHandler != nil {
|
if app.anteHandler != nil {
|
||||||
newCtx, result, abort := app.anteHandler(ctx, tx, (mode == runTxModeSimulate))
|
var anteCtx sdk.Context
|
||||||
|
var msCache sdk.CacheMultiStore
|
||||||
|
|
||||||
|
// Cache wrap context before anteHandler call in case it aborts.
|
||||||
|
// This is required for both CheckTx and DeliverTx.
|
||||||
|
// https://github.com/cosmos/cosmos-sdk/issues/2772
|
||||||
|
// NOTE: Alternatively, we could require that anteHandler ensures that
|
||||||
|
// writes do not happen if aborted/failed. This may have some
|
||||||
|
// performance benefits, but it'll be more difficult to get right.
|
||||||
|
anteCtx, msCache = app.cacheTxContext(ctx, txBytes)
|
||||||
|
|
||||||
|
newCtx, result, abort := app.anteHandler(anteCtx, tx, (mode == runTxModeSimulate))
|
||||||
if abort {
|
if abort {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
if !newCtx.IsZero() {
|
if !newCtx.IsZero() {
|
||||||
ctx = newCtx
|
// At this point, newCtx.MultiStore() is cache wrapped,
|
||||||
|
// or something else replaced by anteHandler.
|
||||||
|
// We want the original ms, not one which was cache-wrapped
|
||||||
|
// for the ante handler.
|
||||||
|
ctx = newCtx.WithMultiStore(ms)
|
||||||
}
|
}
|
||||||
|
msCache.Write()
|
||||||
gasWanted = result.GasWanted
|
gasWanted = result.GasWanted
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode == runTxModeSimulate {
|
if mode == runTxModeCheck {
|
||||||
result = app.runMsgs(ctx, msgs, mode)
|
|
||||||
result.GasWanted = gasWanted
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep the state in a transient CacheWrap in case processing the messages
|
// Create a new context based off of the existing context with a cache wrapped
|
||||||
// fails.
|
// multi-store in case message processing fails.
|
||||||
msCache = getState(app, mode).CacheMultiStore()
|
runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes)
|
||||||
if msCache.TracingEnabled() {
|
result = app.runMsgs(runMsgCtx, msgs, mode)
|
||||||
msCache = msCache.WithTracingContext(sdk.TraceContext(
|
|
||||||
map[string]interface{}{"txHash": cmn.HexBytes(tmhash.Sum(txBytes)).String()},
|
|
||||||
)).(sdk.CacheMultiStore)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = ctx.WithMultiStore(msCache)
|
|
||||||
result = app.runMsgs(ctx, msgs, mode)
|
|
||||||
result.GasWanted = gasWanted
|
result.GasWanted = gasWanted
|
||||||
|
|
||||||
|
if mode == runTxModeSimulate {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// only update state if all messages pass
|
// only update state if all messages pass
|
||||||
if result.IsOK() {
|
if result.IsOK() {
|
||||||
msCache.Write()
|
msCache.Write()
|
||||||
|
@ -679,14 +791,6 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc
|
||||||
// Implements ABCI
|
// Implements ABCI
|
||||||
func (app *BaseApp) Commit() (res abci.ResponseCommit) {
|
func (app *BaseApp) Commit() (res abci.ResponseCommit) {
|
||||||
header := app.deliverState.ctx.BlockHeader()
|
header := app.deliverState.ctx.BlockHeader()
|
||||||
/*
|
|
||||||
// Write the latest Header to the store
|
|
||||||
headerBytes, err := proto.Marshal(&header)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
app.db.SetSync(dbHeaderKey, headerBytes)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Write the Deliver state and commit the MultiStore
|
// Write the Deliver state and commit the MultiStore
|
||||||
app.deliverState.ms.Write()
|
app.deliverState.ms.Write()
|
||||||
|
|
|
@ -56,7 +56,9 @@ func setupBaseApp(t *testing.T, options ...func(*BaseApp)) *BaseApp {
|
||||||
require.Equal(t, t.Name(), app.Name())
|
require.Equal(t, t.Name(), app.Name())
|
||||||
|
|
||||||
// no stores are mounted
|
// no stores are mounted
|
||||||
require.Panics(t, func() { app.LoadLatestVersion(capKey1) })
|
require.Panics(t, func() {
|
||||||
|
app.LoadLatestVersion(capKey1)
|
||||||
|
})
|
||||||
|
|
||||||
app.MountStoresIAVL(capKey1, capKey2)
|
app.MountStoresIAVL(capKey1, capKey2)
|
||||||
|
|
||||||
|
@ -282,12 +284,24 @@ func TestInitChainer(t *testing.T) {
|
||||||
|
|
||||||
// Simple tx with a list of Msgs.
|
// Simple tx with a list of Msgs.
|
||||||
type txTest struct {
|
type txTest struct {
|
||||||
Msgs []sdk.Msg
|
Msgs []sdk.Msg
|
||||||
Counter int64
|
Counter int64
|
||||||
|
FailOnAnte bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *txTest) setFailOnAnte(fail bool) {
|
||||||
|
tx.FailOnAnte = fail
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *txTest) setFailOnHandler(fail bool) {
|
||||||
|
for i, msg := range tx.Msgs {
|
||||||
|
tx.Msgs[i] = msgCounter{msg.(msgCounter).Counter, fail}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Tx
|
// Implements Tx
|
||||||
func (tx txTest) GetMsgs() []sdk.Msg { return tx.Msgs }
|
func (tx txTest) GetMsgs() []sdk.Msg { return tx.Msgs }
|
||||||
|
func (tx txTest) ValidateBasic() sdk.Error { return nil }
|
||||||
|
|
||||||
const (
|
const (
|
||||||
routeMsgCounter = "msgCounter"
|
routeMsgCounter = "msgCounter"
|
||||||
|
@ -297,7 +311,8 @@ const (
|
||||||
// ValidateBasic() fails on negative counters.
|
// ValidateBasic() fails on negative counters.
|
||||||
// Otherwise it's up to the handlers
|
// Otherwise it's up to the handlers
|
||||||
type msgCounter struct {
|
type msgCounter struct {
|
||||||
Counter int64
|
Counter int64
|
||||||
|
FailOnHandler bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Msg
|
// Implements Msg
|
||||||
|
@ -315,9 +330,9 @@ func (msg msgCounter) ValidateBasic() sdk.Error {
|
||||||
func newTxCounter(txInt int64, msgInts ...int64) *txTest {
|
func newTxCounter(txInt int64, msgInts ...int64) *txTest {
|
||||||
var msgs []sdk.Msg
|
var msgs []sdk.Msg
|
||||||
for _, msgInt := range msgInts {
|
for _, msgInt := range msgInts {
|
||||||
msgs = append(msgs, msgCounter{msgInt})
|
msgs = append(msgs, msgCounter{msgInt, false})
|
||||||
}
|
}
|
||||||
return &txTest{msgs, txInt}
|
return &txTest{msgs, txInt, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// a msg we dont know how to route
|
// a msg we dont know how to route
|
||||||
|
@ -369,8 +384,13 @@ func testTxDecoder(cdc *codec.Codec) sdk.TxDecoder {
|
||||||
func anteHandlerTxTest(t *testing.T, capKey *sdk.KVStoreKey, storeKey []byte) sdk.AnteHandler {
|
func anteHandlerTxTest(t *testing.T, capKey *sdk.KVStoreKey, storeKey []byte) sdk.AnteHandler {
|
||||||
return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
||||||
store := ctx.KVStore(capKey)
|
store := ctx.KVStore(capKey)
|
||||||
msgCounter := tx.(txTest).Counter
|
txTest := tx.(txTest)
|
||||||
res = incrementingCounter(t, store, storeKey, msgCounter)
|
|
||||||
|
if txTest.FailOnAnte {
|
||||||
|
return newCtx, sdk.ErrInternal("ante handler failure").Result(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
res = incrementingCounter(t, store, storeKey, txTest.Counter)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,10 +401,15 @@ func handlerMsgCounter(t *testing.T, capKey *sdk.KVStoreKey, deliverKey []byte)
|
||||||
var msgCount int64
|
var msgCount int64
|
||||||
switch m := msg.(type) {
|
switch m := msg.(type) {
|
||||||
case *msgCounter:
|
case *msgCounter:
|
||||||
|
if m.FailOnHandler {
|
||||||
|
return sdk.ErrInternal("message handler failure").Result()
|
||||||
|
}
|
||||||
|
|
||||||
msgCount = m.Counter
|
msgCount = m.Counter
|
||||||
case *msgCounter2:
|
case *msgCounter2:
|
||||||
msgCount = m.Counter
|
msgCount = m.Counter
|
||||||
}
|
}
|
||||||
|
|
||||||
return incrementingCounter(t, store, deliverKey, msgCount)
|
return incrementingCounter(t, store, deliverKey, msgCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,6 +516,7 @@ func TestDeliverTx(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||||
|
app.InitChain(abci.RequestInitChain{})
|
||||||
|
|
||||||
// Create same codec used in txDecoder
|
// Create same codec used in txDecoder
|
||||||
codec := codec.New()
|
codec := codec.New()
|
||||||
|
@ -596,7 +622,7 @@ func TestConcurrentCheckDeliver(t *testing.T) {
|
||||||
// Simulate() and Query("/app/simulate", txBytes) should give
|
// Simulate() and Query("/app/simulate", txBytes) should give
|
||||||
// the same results.
|
// the same results.
|
||||||
func TestSimulateTx(t *testing.T) {
|
func TestSimulateTx(t *testing.T) {
|
||||||
gasConsumed := int64(5)
|
gasConsumed := uint64(5)
|
||||||
|
|
||||||
anteOpt := func(bapp *BaseApp) {
|
anteOpt := func(bapp *BaseApp) {
|
||||||
bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
||||||
|
@ -678,7 +704,8 @@ func TestRunInvalidTransaction(t *testing.T) {
|
||||||
{
|
{
|
||||||
emptyTx := &txTest{}
|
emptyTx := &txTest{}
|
||||||
err := app.Deliver(emptyTx)
|
err := app.Deliver(emptyTx)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeInternal), err.Code)
|
require.EqualValues(t, sdk.CodeInternal, err.Code)
|
||||||
|
require.EqualValues(t, sdk.CodespaceRoot, err.Codespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transaction where ValidateBasic fails
|
// Transaction where ValidateBasic fails
|
||||||
|
@ -701,7 +728,8 @@ func TestRunInvalidTransaction(t *testing.T) {
|
||||||
tx := testCase.tx
|
tx := testCase.tx
|
||||||
res := app.Deliver(tx)
|
res := app.Deliver(tx)
|
||||||
if testCase.fail {
|
if testCase.fail {
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeInvalidSequence), res.Code)
|
require.EqualValues(t, sdk.CodeInvalidSequence, res.Code)
|
||||||
|
require.EqualValues(t, sdk.CodespaceRoot, res.Codespace)
|
||||||
} else {
|
} else {
|
||||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||||
}
|
}
|
||||||
|
@ -710,13 +738,15 @@ func TestRunInvalidTransaction(t *testing.T) {
|
||||||
|
|
||||||
// Transaction with no known route
|
// Transaction with no known route
|
||||||
{
|
{
|
||||||
unknownRouteTx := txTest{[]sdk.Msg{msgNoRoute{}}, 0}
|
unknownRouteTx := txTest{[]sdk.Msg{msgNoRoute{}}, 0, false}
|
||||||
err := app.Deliver(unknownRouteTx)
|
err := app.Deliver(unknownRouteTx)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), err.Code)
|
require.EqualValues(t, sdk.CodeUnknownRequest, err.Code)
|
||||||
|
require.EqualValues(t, sdk.CodespaceRoot, err.Codespace)
|
||||||
|
|
||||||
unknownRouteTx = txTest{[]sdk.Msg{msgCounter{}, msgNoRoute{}}, 0}
|
unknownRouteTx = txTest{[]sdk.Msg{msgCounter{}, msgNoRoute{}}, 0, false}
|
||||||
err = app.Deliver(unknownRouteTx)
|
err = app.Deliver(unknownRouteTx)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), err.Code)
|
require.EqualValues(t, sdk.CodeUnknownRequest, err.Code)
|
||||||
|
require.EqualValues(t, sdk.CodespaceRoot, err.Codespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transaction with an unregistered message
|
// Transaction with an unregistered message
|
||||||
|
@ -732,13 +762,14 @@ func TestRunInvalidTransaction(t *testing.T) {
|
||||||
txBytes, err := newCdc.MarshalBinaryLengthPrefixed(tx)
|
txBytes, err := newCdc.MarshalBinaryLengthPrefixed(tx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
res := app.DeliverTx(txBytes)
|
res := app.DeliverTx(txBytes)
|
||||||
require.EqualValues(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeTxDecode), res.Code)
|
require.EqualValues(t, sdk.CodeTxDecode, res.Code)
|
||||||
|
require.EqualValues(t, sdk.CodespaceRoot, res.Codespace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that transactions exceeding gas limits fail
|
// Test that transactions exceeding gas limits fail
|
||||||
func TestTxGasLimits(t *testing.T) {
|
func TestTxGasLimits(t *testing.T) {
|
||||||
gasGranted := int64(10)
|
gasGranted := uint64(10)
|
||||||
anteOpt := func(bapp *BaseApp) {
|
anteOpt := func(bapp *BaseApp) {
|
||||||
bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
||||||
newCtx = ctx.WithGasMeter(sdk.NewGasMeter(gasGranted))
|
newCtx = ctx.WithGasMeter(sdk.NewGasMeter(gasGranted))
|
||||||
|
@ -763,7 +794,7 @@ func TestTxGasLimits(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
count := tx.(*txTest).Counter
|
count := tx.(*txTest).Counter
|
||||||
newCtx.GasMeter().ConsumeGas(count, "counter-ante")
|
newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante")
|
||||||
res = sdk.Result{
|
res = sdk.Result{
|
||||||
GasWanted: gasGranted,
|
GasWanted: gasGranted,
|
||||||
}
|
}
|
||||||
|
@ -775,7 +806,7 @@ func TestTxGasLimits(t *testing.T) {
|
||||||
routerOpt := func(bapp *BaseApp) {
|
routerOpt := func(bapp *BaseApp) {
|
||||||
bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
count := msg.(msgCounter).Counter
|
count := msg.(msgCounter).Counter
|
||||||
ctx.GasMeter().ConsumeGas(count, "counter-handler")
|
ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler")
|
||||||
return sdk.Result{}
|
return sdk.Result{}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -786,7 +817,7 @@ func TestTxGasLimits(t *testing.T) {
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
tx *txTest
|
tx *txTest
|
||||||
gasUsed int64
|
gasUsed uint64
|
||||||
fail bool
|
fail bool
|
||||||
}{
|
}{
|
||||||
{newTxCounter(0, 0), 0, false},
|
{newTxCounter(0, 0), 0, false},
|
||||||
|
@ -819,7 +850,181 @@ func TestTxGasLimits(t *testing.T) {
|
||||||
if !tc.fail {
|
if !tc.fail {
|
||||||
require.True(t, res.IsOK(), fmt.Sprintf("%d: %v, %v", i, tc, res))
|
require.True(t, res.IsOK(), fmt.Sprintf("%d: %v, %v", i, tc, res))
|
||||||
} else {
|
} else {
|
||||||
require.Equal(t, res.Code, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOutOfGas), fmt.Sprintf("%d: %v, %v", i, tc, res))
|
require.Equal(t, sdk.CodeOutOfGas, res.Code, fmt.Sprintf("%d: %v, %v", i, tc, res))
|
||||||
|
require.Equal(t, sdk.CodespaceRoot, res.Codespace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that transactions exceeding gas limits fail
|
||||||
|
func TestMaxBlockGasLimits(t *testing.T) {
|
||||||
|
gasGranted := uint64(10)
|
||||||
|
anteOpt := func(bapp *BaseApp) {
|
||||||
|
bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
||||||
|
newCtx = ctx.WithGasMeter(sdk.NewGasMeter(gasGranted))
|
||||||
|
|
||||||
|
// NOTE/TODO/XXX:
|
||||||
|
// AnteHandlers must have their own defer/recover in order
|
||||||
|
// for the BaseApp to know how much gas was used 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 = gasGranted
|
||||||
|
res.GasUsed = newCtx.GasMeter().GasConsumed()
|
||||||
|
default:
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
count := tx.(*txTest).Counter
|
||||||
|
newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante")
|
||||||
|
res = sdk.Result{
|
||||||
|
GasWanted: gasGranted,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
routerOpt := func(bapp *BaseApp) {
|
||||||
|
bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
|
count := msg.(msgCounter).Counter
|
||||||
|
ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler")
|
||||||
|
return sdk.Result{}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||||
|
app.InitChain(abci.RequestInitChain{
|
||||||
|
ConsensusParams: &abci.ConsensusParams{
|
||||||
|
BlockSize: &abci.BlockSizeParams{
|
||||||
|
MaxGas: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
tx *txTest
|
||||||
|
numDelivers int
|
||||||
|
gasUsedPerDeliver uint64
|
||||||
|
fail bool
|
||||||
|
failAfterDeliver int
|
||||||
|
}{
|
||||||
|
{newTxCounter(0, 0), 0, 0, false, 0},
|
||||||
|
{newTxCounter(9, 1), 2, 10, false, 0},
|
||||||
|
{newTxCounter(10, 0), 3, 10, false, 0},
|
||||||
|
{newTxCounter(10, 0), 10, 10, false, 0},
|
||||||
|
{newTxCounter(2, 7), 11, 9, false, 0},
|
||||||
|
{newTxCounter(10, 0), 10, 10, false, 0}, // hit the limit but pass
|
||||||
|
|
||||||
|
{newTxCounter(10, 0), 11, 10, true, 10},
|
||||||
|
{newTxCounter(10, 0), 15, 10, true, 10},
|
||||||
|
{newTxCounter(9, 0), 12, 9, true, 11}, // fly past the limit
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
fmt.Printf("debug i: %v\n", i)
|
||||||
|
tx := tc.tx
|
||||||
|
|
||||||
|
// reset the block gas
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{})
|
||||||
|
|
||||||
|
// execute the transaction multiple times
|
||||||
|
for j := 0; j < tc.numDelivers; j++ {
|
||||||
|
res := app.Deliver(tx)
|
||||||
|
|
||||||
|
ctx := app.getState(runTxModeDeliver).ctx
|
||||||
|
blockGasUsed := ctx.BlockGasMeter().GasConsumed()
|
||||||
|
|
||||||
|
// check for failed transactions
|
||||||
|
if tc.fail && (j+1) > tc.failAfterDeliver {
|
||||||
|
require.Equal(t, res.Code, sdk.CodeOutOfGas, fmt.Sprintf("%d: %v, %v", i, tc, res))
|
||||||
|
require.Equal(t, res.Codespace, sdk.CodespaceRoot, fmt.Sprintf("%d: %v, %v", i, tc, res))
|
||||||
|
require.True(t, ctx.BlockGasMeter().IsOutOfGas())
|
||||||
|
} else {
|
||||||
|
// check gas used and wanted
|
||||||
|
expBlockGasUsed := tc.gasUsedPerDeliver * uint64(j+1)
|
||||||
|
require.Equal(t, expBlockGasUsed, blockGasUsed,
|
||||||
|
fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, res))
|
||||||
|
|
||||||
|
require.True(t, res.IsOK(), fmt.Sprintf("%d,%d: %v, %v", i, j, tc, res))
|
||||||
|
require.False(t, ctx.BlockGasMeter().IsPastLimit())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBaseAppAnteHandler(t *testing.T) {
|
||||||
|
anteKey := []byte("ante-key")
|
||||||
|
anteOpt := func(bapp *BaseApp) {
|
||||||
|
bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
deliverKey := []byte("deliver-key")
|
||||||
|
routerOpt := func(bapp *BaseApp) {
|
||||||
|
bapp.Router().AddRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
cdc := codec.New()
|
||||||
|
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||||
|
|
||||||
|
app.InitChain(abci.RequestInitChain{})
|
||||||
|
registerTestCodec(cdc)
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{})
|
||||||
|
|
||||||
|
// execute a tx that will fail ante handler execution
|
||||||
|
//
|
||||||
|
// NOTE: State should not be mutated here. This will be implicitly checked by
|
||||||
|
// the next txs ante handler execution (anteHandlerTxTest).
|
||||||
|
tx := newTxCounter(0, 0)
|
||||||
|
tx.setFailOnAnte(true)
|
||||||
|
txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
res := app.DeliverTx(txBytes)
|
||||||
|
require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||||
|
|
||||||
|
ctx := app.getState(runTxModeDeliver).ctx
|
||||||
|
store := ctx.KVStore(capKey1)
|
||||||
|
require.Equal(t, int64(0), getIntFromStore(store, anteKey))
|
||||||
|
|
||||||
|
// execute at tx that will pass the ante handler (the checkTx state should
|
||||||
|
// mutate) but will fail the message handler
|
||||||
|
tx = newTxCounter(0, 0)
|
||||||
|
tx.setFailOnHandler(true)
|
||||||
|
|
||||||
|
txBytes, err = cdc.MarshalBinaryLengthPrefixed(tx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res = app.DeliverTx(txBytes)
|
||||||
|
require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||||
|
|
||||||
|
ctx = app.getState(runTxModeDeliver).ctx
|
||||||
|
store = ctx.KVStore(capKey1)
|
||||||
|
require.Equal(t, int64(1), getIntFromStore(store, anteKey))
|
||||||
|
require.Equal(t, int64(0), getIntFromStore(store, deliverKey))
|
||||||
|
|
||||||
|
// execute a successful ante handler and message execution where state is
|
||||||
|
// implicitly checked by previous tx executions
|
||||||
|
tx = newTxCounter(1, 0)
|
||||||
|
|
||||||
|
txBytes, err = cdc.MarshalBinaryLengthPrefixed(tx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
res = app.DeliverTx(txBytes)
|
||||||
|
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||||
|
|
||||||
|
ctx = app.getState(runTxModeDeliver).ctx
|
||||||
|
store = ctx.KVStore(capKey1)
|
||||||
|
require.Equal(t, int64(2), getIntFromStore(store, anteKey))
|
||||||
|
require.Equal(t, int64(1), getIntFromStore(store, deliverKey))
|
||||||
|
|
||||||
|
// commit
|
||||||
|
app.EndBlock(abci.RequestEndBlock{})
|
||||||
|
app.Commit()
|
||||||
|
}
|
||||||
|
|
|
@ -175,10 +175,22 @@ func (ctx CLIContext) WithCodec(cdc *codec.Codec) CLIContext {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAccountDecoder gets the account decoder for auth.DefaultAccount.
|
||||||
|
func GetAccountDecoder(cdc *codec.Codec) auth.AccountDecoder {
|
||||||
|
return func(accBytes []byte) (acct auth.Account, err error) {
|
||||||
|
err = cdc.UnmarshalBinaryBare(accBytes, &acct)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acct, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithAccountDecoder returns a copy of the context with an updated account
|
// WithAccountDecoder returns a copy of the context with an updated account
|
||||||
// decoder.
|
// decoder.
|
||||||
func (ctx CLIContext) WithAccountDecoder(decoder auth.AccountDecoder) CLIContext {
|
func (ctx CLIContext) WithAccountDecoder(cdc *codec.Codec) CLIContext {
|
||||||
ctx.AccDecoder = decoder
|
ctx.AccDecoder = GetAccountDecoder(cdc)
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (ctx CLIContext) GetFromName() (string, error) {
|
||||||
|
|
||||||
// GetAccountNumber returns the next account number for the given account
|
// GetAccountNumber returns the next account number for the given account
|
||||||
// address.
|
// address.
|
||||||
func (ctx CLIContext) GetAccountNumber(address []byte) (int64, error) {
|
func (ctx CLIContext) GetAccountNumber(address []byte) (uint64, error) {
|
||||||
account, err := ctx.GetAccount(address)
|
account, err := ctx.GetAccount(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -103,7 +103,7 @@ func (ctx CLIContext) GetAccountNumber(address []byte) (int64, error) {
|
||||||
|
|
||||||
// GetAccountSequence returns the sequence number for the given account
|
// GetAccountSequence returns the sequence number for the given account
|
||||||
// address.
|
// address.
|
||||||
func (ctx CLIContext) GetAccountSequence(address []byte) (int64, error) {
|
func (ctx CLIContext) GetAccountSequence(address []byte) (uint64, error) {
|
||||||
account, err := ctx.GetAccount(address)
|
account, err := ctx.GetAccount(address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|
|
@ -17,25 +17,32 @@ const (
|
||||||
DefaultGasLimit = 200000
|
DefaultGasLimit = 200000
|
||||||
GasFlagSimulate = "simulate"
|
GasFlagSimulate = "simulate"
|
||||||
|
|
||||||
FlagUseLedger = "ledger"
|
FlagUseLedger = "ledger"
|
||||||
FlagChainID = "chain-id"
|
FlagChainID = "chain-id"
|
||||||
FlagNode = "node"
|
FlagNode = "node"
|
||||||
FlagHeight = "height"
|
FlagHeight = "height"
|
||||||
FlagGas = "gas"
|
FlagGas = "gas"
|
||||||
FlagGasAdjustment = "gas-adjustment"
|
FlagGasAdjustment = "gas-adjustment"
|
||||||
FlagTrustNode = "trust-node"
|
FlagTrustNode = "trust-node"
|
||||||
FlagFrom = "from"
|
FlagFrom = "from"
|
||||||
FlagName = "name"
|
FlagName = "name"
|
||||||
FlagAccountNumber = "account-number"
|
FlagAccountNumber = "account-number"
|
||||||
FlagSequence = "sequence"
|
FlagSequence = "sequence"
|
||||||
FlagMemo = "memo"
|
FlagMemo = "memo"
|
||||||
FlagFee = "fee"
|
FlagFee = "fee"
|
||||||
FlagAsync = "async"
|
FlagAsync = "async"
|
||||||
FlagJson = "json"
|
FlagJson = "json"
|
||||||
FlagPrintResponse = "print-response"
|
FlagPrintResponse = "print-response"
|
||||||
FlagDryRun = "dry-run"
|
FlagDryRun = "dry-run"
|
||||||
FlagGenerateOnly = "generate-only"
|
FlagGenerateOnly = "generate-only"
|
||||||
FlagIndentResponse = "indent"
|
FlagIndentResponse = "indent"
|
||||||
|
FlagListenAddr = "laddr"
|
||||||
|
FlagCORS = "cors"
|
||||||
|
FlagMaxOpenConnections = "max-open"
|
||||||
|
FlagInsecure = "insecure"
|
||||||
|
FlagSSLHosts = "ssl-hosts"
|
||||||
|
FlagSSLCertFile = "ssl-certfile"
|
||||||
|
FlagSSLKeyFile = "ssl-keyfile"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LineBreak can be included in a command list to provide a blank line
|
// LineBreak can be included in a command list to provide a blank line
|
||||||
|
@ -67,8 +74,8 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
for _, c := range cmds {
|
for _, c := range cmds {
|
||||||
c.Flags().Bool(FlagIndentResponse, false, "Add indent to JSON response")
|
c.Flags().Bool(FlagIndentResponse, false, "Add indent to JSON response")
|
||||||
c.Flags().String(FlagFrom, "", "Name or address of private key with which to sign")
|
c.Flags().String(FlagFrom, "", "Name or address of private key with which to sign")
|
||||||
c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
|
c.Flags().Uint64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
|
||||||
c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx")
|
c.Flags().Uint64(FlagSequence, 0, "Sequence number to sign the tx")
|
||||||
c.Flags().String(FlagMemo, "", "Memo to send along with transaction")
|
c.Flags().String(FlagMemo, "", "Memo to send along with transaction")
|
||||||
c.Flags().String(FlagFee, "", "Fee to pay along with transaction")
|
c.Flags().String(FlagFee, "", "Fee to pay along with transaction")
|
||||||
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
|
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
|
||||||
|
@ -92,12 +99,32 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterRestServerFlags registers the flags required for rest server
|
||||||
|
func RegisterRestServerFlags(cmd *cobra.Command) *cobra.Command {
|
||||||
|
cmd.Flags().String(FlagListenAddr, "tcp://localhost:1317", "The address for the server to listen on")
|
||||||
|
cmd.Flags().Bool(FlagInsecure, false, "Do not set up SSL/TLS layer")
|
||||||
|
cmd.Flags().String(FlagSSLHosts, "", "Comma-separated hostnames and IPs to generate a certificate for")
|
||||||
|
cmd.Flags().String(FlagSSLCertFile, "", "Path to a SSL certificate file. If not supplied, a self-signed certificate will be generated.")
|
||||||
|
cmd.Flags().String(FlagSSLKeyFile, "", "Path to a key file; ignored if a certificate file is not supplied.")
|
||||||
|
cmd.Flags().String(FlagCORS, "", "Set the domains that can make CORS requests (* for all)")
|
||||||
|
cmd.Flags().String(FlagChainID, "", "Chain ID of Tendermint node")
|
||||||
|
cmd.Flags().String(FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
|
||||||
|
cmd.Flags().Int(FlagMaxOpenConnections, 1000, "The number of maximum open connections")
|
||||||
|
cmd.Flags().Bool(FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
||||||
|
cmd.Flags().Bool(FlagIndentResponse, false, "Add indent to JSON response")
|
||||||
|
|
||||||
|
viper.BindPFlag(FlagTrustNode, cmd.Flags().Lookup(FlagTrustNode))
|
||||||
|
viper.BindPFlag(FlagChainID, cmd.Flags().Lookup(FlagChainID))
|
||||||
|
viper.BindPFlag(FlagNode, cmd.Flags().Lookup(FlagNode))
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
// Gas flag parsing functions
|
// Gas flag parsing functions
|
||||||
|
|
||||||
// GasSetting encapsulates the possible values passed through the --gas flag.
|
// GasSetting encapsulates the possible values passed through the --gas flag.
|
||||||
type GasSetting struct {
|
type GasSetting struct {
|
||||||
Simulate bool
|
Simulate bool
|
||||||
Gas int64
|
Gas uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type returns the flag's value type.
|
// Type returns the flag's value type.
|
||||||
|
@ -113,18 +140,18 @@ func (v *GasSetting) String() string {
|
||||||
if v.Simulate {
|
if v.Simulate {
|
||||||
return GasFlagSimulate
|
return GasFlagSimulate
|
||||||
}
|
}
|
||||||
return strconv.FormatInt(v.Gas, 10)
|
return strconv.FormatUint(v.Gas, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseGasFlag parses the value of the --gas flag.
|
// ParseGasFlag parses the value of the --gas flag.
|
||||||
func ReadGasFlag(s string) (simulate bool, gas int64, err error) {
|
func ReadGasFlag(s string) (simulate bool, gas uint64, err error) {
|
||||||
switch s {
|
switch s {
|
||||||
case "":
|
case "":
|
||||||
gas = DefaultGasLimit
|
gas = DefaultGasLimit
|
||||||
case GasFlagSimulate:
|
case GasFlagSimulate:
|
||||||
simulate = true
|
simulate = true
|
||||||
default:
|
default:
|
||||||
gas, err = strconv.ParseInt(s, 10, 64)
|
gas, err = strconv.ParseUint(s, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("gas must be either integer or %q", GasFlagSimulate)
|
err = fmt.Errorf("gas must be either integer or %q", GasFlagSimulate)
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,20 +2,17 @@ package keys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// KeyDBName is the directory under root where we store the keys
|
// KeyDBName is the directory under root where we store the keys
|
||||||
|
|
|
@ -284,7 +284,7 @@ func TestCoinSend(t *testing.T) {
|
||||||
|
|
||||||
// test failure with negative gas
|
// test failure with negative gas
|
||||||
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "-200", 0, "")
|
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "-200", 0, "")
|
||||||
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
|
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
|
||||||
|
|
||||||
// test failure with 0 gas
|
// test failure with 0 gas
|
||||||
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "0", 0, "")
|
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, "0", 0, "")
|
||||||
|
@ -390,8 +390,8 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
|
||||||
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &resultTx))
|
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &resultTx))
|
||||||
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
require.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||||
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||||
require.Equal(t, gasEstimate, resultTx.DeliverTx.GasWanted)
|
require.Equal(t, gasEstimate, uint64(resultTx.DeliverTx.GasWanted))
|
||||||
require.Equal(t, gasEstimate, resultTx.DeliverTx.GasUsed)
|
require.Equal(t, gasEstimate, uint64(resultTx.DeliverTx.GasUsed))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTxs(t *testing.T) {
|
func TestTxs(t *testing.T) {
|
||||||
|
@ -696,7 +696,7 @@ func TestDeposit(t *testing.T) {
|
||||||
func TestVote(t *testing.T) {
|
func TestVote(t *testing.T) {
|
||||||
name, password := "test", "1234567890"
|
name, password := "test", "1234567890"
|
||||||
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
|
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
|
||||||
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
|
cleanup, _, operAddrs, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
// create SubmitProposal TX
|
// create SubmitProposal TX
|
||||||
|
@ -714,7 +714,7 @@ func TestVote(t *testing.T) {
|
||||||
proposal := getProposal(t, port, proposalID)
|
proposal := getProposal(t, port, proposalID)
|
||||||
require.Equal(t, "Test", proposal.GetTitle())
|
require.Equal(t, "Test", proposal.GetTitle())
|
||||||
|
|
||||||
// create SubmitProposal TX
|
// deposit
|
||||||
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID, 5)
|
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID, 5)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
@ -722,7 +722,7 @@ func TestVote(t *testing.T) {
|
||||||
proposal = getProposal(t, port, proposalID)
|
proposal = getProposal(t, port, proposalID)
|
||||||
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus())
|
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus())
|
||||||
|
|
||||||
// create SubmitProposal TX
|
// vote
|
||||||
resultTx = doVote(t, port, seed, name, password, addr, proposalID)
|
resultTx = doVote(t, port, seed, name, password, addr, proposalID)
|
||||||
tests.WaitForHeight(resultTx.Height+1, port)
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
@ -734,6 +734,20 @@ func TestVote(t *testing.T) {
|
||||||
vote := getVote(t, port, proposalID, addr)
|
vote := getVote(t, port, proposalID, addr)
|
||||||
require.Equal(t, proposalID, vote.ProposalID)
|
require.Equal(t, proposalID, vote.ProposalID)
|
||||||
require.Equal(t, gov.OptionYes, vote.Option)
|
require.Equal(t, gov.OptionYes, vote.Option)
|
||||||
|
|
||||||
|
tally := getTally(t, port, proposalID)
|
||||||
|
require.Equal(t, sdk.ZeroDec(), tally.Yes, "tally should be 0 as the address is not bonded")
|
||||||
|
|
||||||
|
// create bond TX
|
||||||
|
resultTx = doDelegate(t, port, seed, name, password, addr, operAddrs[0], 60)
|
||||||
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
// vote
|
||||||
|
resultTx = doVote(t, port, seed, name, password, addr, proposalID)
|
||||||
|
tests.WaitForHeight(resultTx.Height+1, port)
|
||||||
|
|
||||||
|
tally = getTally(t, port, proposalID)
|
||||||
|
require.Equal(t, sdk.NewDec(60), tally.Yes, "tally should be equal to the amount delegated")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnjail(t *testing.T) {
|
func TestUnjail(t *testing.T) {
|
||||||
|
@ -853,11 +867,11 @@ func TestProposalsQuery(t *testing.T) {
|
||||||
require.Equal(t, proposalID3, (proposals[2]).GetProposalID())
|
require.Equal(t, proposalID3, (proposals[2]).GetProposalID())
|
||||||
|
|
||||||
// Test query deposited by addr1
|
// Test query deposited by addr1
|
||||||
proposals = getProposalsFilterDepositer(t, port, addrs[0])
|
proposals = getProposalsFilterDepositor(t, port, addrs[0])
|
||||||
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
|
||||||
|
|
||||||
// Test query deposited by addr2
|
// Test query deposited by addr2
|
||||||
proposals = getProposalsFilterDepositer(t, port, addrs[1])
|
proposals = getProposalsFilterDepositor(t, port, addrs[1])
|
||||||
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
||||||
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
|
require.Equal(t, proposalID3, (proposals[1]).GetProposalID())
|
||||||
|
|
||||||
|
@ -871,7 +885,7 @@ func TestProposalsQuery(t *testing.T) {
|
||||||
require.Equal(t, proposalID3, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID3, (proposals[0]).GetProposalID())
|
||||||
|
|
||||||
// Test query voted and deposited by addr1
|
// Test query voted and deposited by addr1
|
||||||
proposals = getProposalsFilterVoterDepositer(t, port, addrs[0], addrs[0])
|
proposals = getProposalsFilterVoterDepositor(t, port, addrs[0], addrs[0])
|
||||||
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
require.Equal(t, proposalID2, (proposals[0]).GetProposalID())
|
||||||
|
|
||||||
// Test query votes on Proposal 2
|
// Test query votes on Proposal 2
|
||||||
|
@ -1381,8 +1395,8 @@ func getDeposits(t *testing.T, port string, proposalID uint64) []gov.Deposit {
|
||||||
return deposits
|
return deposits
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDeposit(t *testing.T, port string, proposalID uint64, depositerAddr sdk.AccAddress) gov.Deposit {
|
func getDeposit(t *testing.T, port string, proposalID uint64, depositorAddr sdk.AccAddress) gov.Deposit {
|
||||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil)
|
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositorAddr), nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
var deposit gov.Deposit
|
var deposit gov.Deposit
|
||||||
err := cdc.UnmarshalJSON([]byte(body), &deposit)
|
err := cdc.UnmarshalJSON([]byte(body), &deposit)
|
||||||
|
@ -1408,6 +1422,15 @@ func getVotes(t *testing.T, port string, proposalID uint64) []gov.Vote {
|
||||||
return votes
|
return votes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getTally(t *testing.T, port string, proposalID uint64) gov.TallyResult {
|
||||||
|
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/tally", proposalID), nil)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
var tally gov.TallyResult
|
||||||
|
err := cdc.UnmarshalJSON([]byte(body), &tally)
|
||||||
|
require.Nil(t, err)
|
||||||
|
return tally
|
||||||
|
}
|
||||||
|
|
||||||
func getProposalsAll(t *testing.T, port string) []gov.Proposal {
|
func getProposalsAll(t *testing.T, port string) []gov.Proposal {
|
||||||
res, body := Request(t, port, "GET", "/gov/proposals", nil)
|
res, body := Request(t, port, "GET", "/gov/proposals", nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
@ -1418,8 +1441,8 @@ func getProposalsAll(t *testing.T, port string) []gov.Proposal {
|
||||||
return proposals
|
return proposals
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProposalsFilterDepositer(t *testing.T, port string, depositerAddr sdk.AccAddress) []gov.Proposal {
|
func getProposalsFilterDepositor(t *testing.T, port string, depositorAddr sdk.AccAddress) []gov.Proposal {
|
||||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositer=%s", depositerAddr), nil)
|
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositor=%s", depositorAddr), nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
var proposals []gov.Proposal
|
var proposals []gov.Proposal
|
||||||
|
@ -1438,8 +1461,8 @@ func getProposalsFilterVoter(t *testing.T, port string, voterAddr sdk.AccAddress
|
||||||
return proposals
|
return proposals
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProposalsFilterVoterDepositer(t *testing.T, port string, voterAddr, depositerAddr sdk.AccAddress) []gov.Proposal {
|
func getProposalsFilterVoterDepositor(t *testing.T, port string, voterAddr, depositorAddr sdk.AccAddress) []gov.Proposal {
|
||||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositer=%s&voter=%s", depositerAddr, voterAddr), nil)
|
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositor=%s&voter=%s", depositorAddr, voterAddr), nil)
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
|
||||||
var proposals []gov.Proposal
|
var proposals []gov.Proposal
|
||||||
|
@ -1501,7 +1524,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
|
||||||
|
|
||||||
// deposit on proposal
|
// deposit on proposal
|
||||||
jsonStr := []byte(fmt.Sprintf(`{
|
jsonStr := []byte(fmt.Sprintf(`{
|
||||||
"depositer": "%s",
|
"depositor": "%s",
|
||||||
"amount": [{ "denom": "%s", "amount": "%d" }],
|
"amount": [{ "denom": "%s", "amount": "%d" }],
|
||||||
"base_req": {
|
"base_req": {
|
||||||
"name": "%s",
|
"name": "%s",
|
||||||
|
|
|
@ -10,176 +10,169 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
keybase "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
|
||||||
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
|
||||||
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
|
||||||
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
|
||||||
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/rakyll/statik/fs"
|
"github.com/rakyll/statik/fs"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
|
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
|
||||||
|
|
||||||
|
// Import statik for light client stuff
|
||||||
|
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
// RestServer represents the Light Client Rest server
|
||||||
flagListenAddr = "laddr"
|
type RestServer struct {
|
||||||
flagCORS = "cors"
|
Mux *mux.Router
|
||||||
flagMaxOpenConnections = "max-open"
|
CliCtx context.CLIContext
|
||||||
flagInsecure = "insecure"
|
KeyBase keybase.Keybase
|
||||||
flagSSLHosts = "ssl-hosts"
|
Cdc *codec.Codec
|
||||||
flagSSLCertFile = "ssl-certfile"
|
|
||||||
flagSSLKeyFile = "ssl-keyfile"
|
log log.Logger
|
||||||
)
|
listener net.Listener
|
||||||
|
fingerprint string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRestServer creates a new rest server instance
|
||||||
|
func NewRestServer(cdc *codec.Codec) *RestServer {
|
||||||
|
r := mux.NewRouter()
|
||||||
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
|
||||||
|
// Register version methods on the router
|
||||||
|
r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET")
|
||||||
|
r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET")
|
||||||
|
|
||||||
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
|
||||||
|
|
||||||
|
return &RestServer{
|
||||||
|
Mux: r,
|
||||||
|
CliCtx: cliCtx,
|
||||||
|
Cdc: cdc,
|
||||||
|
|
||||||
|
log: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RestServer) setKeybase(kb keybase.Keybase) {
|
||||||
|
// If a keybase is passed in, set it and return
|
||||||
|
if kb != nil {
|
||||||
|
rs.KeyBase = kb
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise get the keybase and set it
|
||||||
|
kb, err := keys.GetKeyBase() //XXX
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to open Keybase: %s, exiting...", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
rs.KeyBase = kb
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts the rest server
|
||||||
|
func (rs *RestServer) Start(listenAddr string, sslHosts string,
|
||||||
|
certFile string, keyFile string, maxOpen int, insecure bool) (err error) {
|
||||||
|
|
||||||
|
server.TrapSignal(func() {
|
||||||
|
err := rs.listener.Close()
|
||||||
|
rs.log.Error("error closing listener", "err", err)
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: re-enable insecure mode once #2715 has been addressed
|
||||||
|
if insecure {
|
||||||
|
fmt.Println(
|
||||||
|
"Insecure mode is temporarily disabled, please locally generate an " +
|
||||||
|
"SSL certificate to test. Support will be re-enabled soon!",
|
||||||
|
)
|
||||||
|
// listener, err = tmserver.StartHTTPServer(
|
||||||
|
// listenAddr, handler, logger,
|
||||||
|
// tmserver.Config{MaxOpenConnections: maxOpen},
|
||||||
|
// )
|
||||||
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
if certFile != "" {
|
||||||
|
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
|
||||||
|
err = validateCertKeyFiles(certFile, keyFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// cert/key pair is provided, read the fingerprint
|
||||||
|
rs.fingerprint, err = fingerprintFromFile(certFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if certificate is not supplied, generate a self-signed one
|
||||||
|
certFile, keyFile, rs.fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
os.Remove(certFile)
|
||||||
|
os.Remove(keyFile)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
rs.listener, err = tmserver.StartHTTPAndTLSServer(
|
||||||
|
listenAddr, rs.Mux,
|
||||||
|
certFile, keyFile,
|
||||||
|
rs.log,
|
||||||
|
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rs.log.Info(rs.fingerprint)
|
||||||
|
rs.log.Info("REST server started")
|
||||||
|
}
|
||||||
|
|
||||||
|
// logger.Info("REST server started")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ServeCommand will generate a long-running rest server
|
// ServeCommand will generate a long-running rest server
|
||||||
// (aka Light Client Daemon) that exposes functionality similar
|
// (aka Light Client Daemon) that exposes functionality similar
|
||||||
// to the cli, but over rest
|
// to the cli, but over rest
|
||||||
func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
func (rs *RestServer) ServeCommand() *cobra.Command {
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "rest-server",
|
Use: "rest-server",
|
||||||
Short: "Start LCD (light-client daemon), a local REST server",
|
Short: "Start LCD (light-client daemon), a local REST server",
|
||||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||||
listenAddr := viper.GetString(flagListenAddr)
|
rs.setKeybase(nil)
|
||||||
handler := createHandler(cdc)
|
// Start the rest server and return error if one exists
|
||||||
|
err = rs.Start(
|
||||||
|
viper.GetString(client.FlagListenAddr),
|
||||||
|
viper.GetString(client.FlagSSLHosts),
|
||||||
|
viper.GetString(client.FlagSSLCertFile),
|
||||||
|
viper.GetString(client.FlagSSLKeyFile),
|
||||||
|
viper.GetInt(client.FlagMaxOpenConnections),
|
||||||
|
viper.GetBool(client.FlagInsecure))
|
||||||
|
|
||||||
registerSwaggerUI(handler)
|
return err
|
||||||
|
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
|
|
||||||
maxOpen := viper.GetInt(flagMaxOpenConnections)
|
|
||||||
sslHosts := viper.GetString(flagSSLHosts)
|
|
||||||
certFile := viper.GetString(flagSSLCertFile)
|
|
||||||
keyFile := viper.GetString(flagSSLKeyFile)
|
|
||||||
|
|
||||||
var listener net.Listener
|
|
||||||
var fingerprint string
|
|
||||||
|
|
||||||
server.TrapSignal(func() {
|
|
||||||
err := listener.Close()
|
|
||||||
logger.Error("error closing listener", "err", err)
|
|
||||||
})
|
|
||||||
|
|
||||||
var cleanupFunc func()
|
|
||||||
|
|
||||||
// TODO: re-enable insecure mode once #2715 has been addressed
|
|
||||||
if viper.GetBool(flagInsecure) {
|
|
||||||
fmt.Println(
|
|
||||||
"Insecure mode is temporarily disabled, please locally generate an " +
|
|
||||||
"SSL certificate to test. Support will be re-enabled soon!",
|
|
||||||
)
|
|
||||||
// listener, err = tmserver.StartHTTPServer(
|
|
||||||
// listenAddr, handler, logger,
|
|
||||||
// tmserver.Config{MaxOpenConnections: maxOpen},
|
|
||||||
// )
|
|
||||||
// if err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
} else {
|
|
||||||
if certFile != "" {
|
|
||||||
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
|
|
||||||
err = validateCertKeyFiles(certFile, keyFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// cert/key pair is provided, read the fingerprint
|
|
||||||
fingerprint, err = fingerprintFromFile(certFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if certificate is not supplied, generate a self-signed one
|
|
||||||
certFile, keyFile, fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanupFunc = func() {
|
|
||||||
os.Remove(certFile)
|
|
||||||
os.Remove(keyFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer cleanupFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
listener, err = tmserver.StartHTTPAndTLSServer(
|
|
||||||
listenAddr, handler,
|
|
||||||
certFile, keyFile,
|
|
||||||
logger,
|
|
||||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info(fingerprint)
|
|
||||||
logger.Info("REST server started")
|
|
||||||
}
|
|
||||||
|
|
||||||
// logger.Info("REST server started")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().String(flagListenAddr, "tcp://localhost:1317", "The address for the server to listen on")
|
client.RegisterRestServerFlags(cmd)
|
||||||
cmd.Flags().Bool(flagInsecure, false, "Do not set up SSL/TLS layer")
|
|
||||||
cmd.Flags().String(flagSSLHosts, "", "Comma-separated hostnames and IPs to generate a certificate for")
|
|
||||||
cmd.Flags().String(flagSSLCertFile, "", "Path to a SSL certificate file. If not supplied, a self-signed certificate will be generated.")
|
|
||||||
cmd.Flags().String(flagSSLKeyFile, "", "Path to a key file; ignored if a certificate file is not supplied.")
|
|
||||||
cmd.Flags().String(flagCORS, "", "Set the domains that can make CORS requests (* for all)")
|
|
||||||
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
|
|
||||||
cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
|
|
||||||
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
|
|
||||||
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
|
|
||||||
cmd.Flags().Bool(client.FlagIndentResponse, false, "Add indent to JSON response")
|
|
||||||
|
|
||||||
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
|
|
||||||
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
|
|
||||||
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
|
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func createHandler(cdc *codec.Codec) *mux.Router {
|
func (rs *RestServer) registerSwaggerUI() {
|
||||||
r := mux.NewRouter()
|
|
||||||
|
|
||||||
kb, err := keys.GetKeyBase() //XXX
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
|
||||||
|
|
||||||
// TODO: make more functional? aka r = keys.RegisterRoutes(r)
|
|
||||||
r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET")
|
|
||||||
r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET")
|
|
||||||
|
|
||||||
keys.RegisterRoutes(r, cliCtx.Indent)
|
|
||||||
rpc.RegisterRoutes(cliCtx, r)
|
|
||||||
tx.RegisterRoutes(cliCtx, r, cdc)
|
|
||||||
auth.RegisterRoutes(cliCtx, r, cdc, "acc")
|
|
||||||
bank.RegisterRoutes(cliCtx, r, cdc, kb)
|
|
||||||
stake.RegisterRoutes(cliCtx, r, cdc, kb)
|
|
||||||
slashing.RegisterRoutes(cliCtx, r, cdc, kb)
|
|
||||||
gov.RegisterRoutes(cliCtx, r, cdc)
|
|
||||||
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func registerSwaggerUI(r *mux.Router) {
|
|
||||||
statikFS, err := fs.New()
|
statikFS, err := fs.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
staticServer := http.FileServer(statikFS)
|
staticServer := http.FileServer(statikFS)
|
||||||
r.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer))
|
rs.Mux.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer))
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateCertKeyFiles(certFile, keyFile string) error {
|
func validateCertKeyFiles(certFile, keyFile string) error {
|
||||||
|
|
|
@ -1226,8 +1226,8 @@ paths:
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: depositer
|
name: depositor
|
||||||
description: depositer address
|
description: depositor address
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
|
@ -1281,7 +1281,7 @@ paths:
|
||||||
properties:
|
properties:
|
||||||
base_req:
|
base_req:
|
||||||
"$ref": "#/definitions/BaseReq"
|
"$ref": "#/definitions/BaseReq"
|
||||||
depositer:
|
depositor:
|
||||||
"$ref": "#/definitions/Address"
|
"$ref": "#/definitions/Address"
|
||||||
amount:
|
amount:
|
||||||
type: array
|
type: array
|
||||||
|
@ -1321,6 +1321,29 @@ paths:
|
||||||
description: Invalid proposal id
|
description: Invalid proposal id
|
||||||
500:
|
500:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
|
/gov/proposals/{proposalId}/tally:
|
||||||
|
get:
|
||||||
|
summary: Get a proposal's tally result at the current time
|
||||||
|
description: Gets a proposal's tally result at the current time. If the proposal is pending deposits (i.e status 'DepositPeriod') it returns an empty tally result.
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
tags:
|
||||||
|
- ICS22
|
||||||
|
parameters:
|
||||||
|
- type: string
|
||||||
|
description: proposal id
|
||||||
|
name: proposalId
|
||||||
|
required: true
|
||||||
|
in: path
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/TallyResult"
|
||||||
|
400:
|
||||||
|
description: Invalid proposal id
|
||||||
|
500:
|
||||||
|
description: Internal Server Error
|
||||||
/gov/proposals/{proposalId}/votes:
|
/gov/proposals/{proposalId}/votes:
|
||||||
post:
|
post:
|
||||||
summary: Vote a proposal
|
summary: Vote a proposal
|
||||||
|
@ -1418,10 +1441,10 @@ paths:
|
||||||
description: Invalid proposal id
|
description: Invalid proposal id
|
||||||
500:
|
500:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
/gov/proposals/{proposalId}/deposits/{depositer}:
|
/gov/proposals/{proposalId}/deposits/{depositor}:
|
||||||
get:
|
get:
|
||||||
summary: Query deposit
|
summary: Query deposit
|
||||||
description: Query deposit by proposalId and depositer address
|
description: Query deposit by proposalId and depositor address
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
tags:
|
tags:
|
||||||
|
@ -1433,8 +1456,8 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
- type: string
|
- type: string
|
||||||
description: Bech32 depositer address
|
description: Bech32 depositor address
|
||||||
name: depositer
|
name: depositor
|
||||||
required: true
|
required: true
|
||||||
in: path
|
in: path
|
||||||
responses:
|
responses:
|
||||||
|
@ -1443,7 +1466,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/Deposit"
|
$ref: "#/definitions/Deposit"
|
||||||
400:
|
400:
|
||||||
description: Invalid proposal id or depositer address
|
description: Invalid proposal id or depositor address
|
||||||
404:
|
404:
|
||||||
description: Found no deposit
|
description: Found no deposit
|
||||||
500:
|
500:
|
||||||
|
@ -1893,16 +1916,7 @@ definitions:
|
||||||
proposal_status:
|
proposal_status:
|
||||||
type: string
|
type: string
|
||||||
tally_result:
|
tally_result:
|
||||||
type: object
|
$ref: "#/definitions/TallyResult"
|
||||||
properties:
|
|
||||||
yes:
|
|
||||||
type: string
|
|
||||||
abstain:
|
|
||||||
type: string
|
|
||||||
no:
|
|
||||||
type: string
|
|
||||||
no_with_veto:
|
|
||||||
type: string
|
|
||||||
submit_time:
|
submit_time:
|
||||||
type: string
|
type: string
|
||||||
total_deposit:
|
total_deposit:
|
||||||
|
@ -1920,8 +1934,23 @@ definitions:
|
||||||
"$ref": "#/definitions/Coin"
|
"$ref": "#/definitions/Coin"
|
||||||
proposal_id:
|
proposal_id:
|
||||||
type: integer
|
type: integer
|
||||||
depositer:
|
depositor:
|
||||||
"$ref": "#/definitions/Address"
|
"$ref": "#/definitions/Address"
|
||||||
|
TallyResult:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
yes:
|
||||||
|
type: string
|
||||||
|
example: "0.0000000000"
|
||||||
|
abstain:
|
||||||
|
type: string
|
||||||
|
example: "0.0000000000"
|
||||||
|
no:
|
||||||
|
type: string
|
||||||
|
example: "0.0000000000"
|
||||||
|
no_with_veto:
|
||||||
|
type: string
|
||||||
|
example: "0.0000000000"
|
||||||
Vote:
|
Vote:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -19,6 +19,8 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||||
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
|
@ -45,6 +47,12 @@ import (
|
||||||
"github.com/tendermint/tendermint/proxy"
|
"github.com/tendermint/tendermint/proxy"
|
||||||
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
|
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
|
authRest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||||
|
bankRest "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||||
|
govRest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||||
|
slashingRest "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
||||||
|
stakeRest "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// makePathname creates a unique pathname for each test. It will panic if it
|
// makePathname creates a unique pathname for each test. It will panic if it
|
||||||
|
@ -103,6 +111,13 @@ func GetKeyBase(t *testing.T) crkeys.Keybase {
|
||||||
return keybase
|
return keybase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTestKeyBase fetches the current testing keybase
|
||||||
|
func GetTestKeyBase(t *testing.T) crkeys.Keybase {
|
||||||
|
keybase, err := keys.GetKeyBaseWithWritePerm()
|
||||||
|
require.NoError(t, err)
|
||||||
|
return keybase
|
||||||
|
}
|
||||||
|
|
||||||
// CreateAddr adds an address to the key store and returns an address and seed.
|
// CreateAddr adds an address to the key store and returns an address and seed.
|
||||||
// It also requires that the key could be created.
|
// It also requires that the key could be created.
|
||||||
func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (sdk.AccAddress, string) {
|
func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (sdk.AccAddress, string) {
|
||||||
|
@ -288,7 +303,7 @@ func InitializeTestLCD(
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress))
|
tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress))
|
||||||
lcd, err := startLCD(logger, listenAddr, cdc)
|
lcd, err := startLCD(logger, listenAddr, cdc, t)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tests.WaitForLCDStart(port)
|
tests.WaitForLCDStart(port)
|
||||||
|
@ -347,8 +362,23 @@ func startTM(
|
||||||
// startLCD starts the LCD.
|
// startLCD starts the LCD.
|
||||||
//
|
//
|
||||||
// NOTE: This causes the thread to block.
|
// NOTE: This causes the thread to block.
|
||||||
func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec) (net.Listener, error) {
|
func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing.T) (net.Listener, error) {
|
||||||
return tmrpc.StartHTTPServer(listenAddr, createHandler(cdc), logger, tmrpc.Config{})
|
rs := NewRestServer(cdc)
|
||||||
|
rs.setKeybase(GetTestKeyBase(t))
|
||||||
|
registerRoutes(rs)
|
||||||
|
return tmrpc.StartHTTPServer(listenAddr, rs.Mux, logger, tmrpc.Config{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: If making updates here also update cmd/gaia/cmd/gaiacli/main.go
|
||||||
|
func registerRoutes(rs *RestServer) {
|
||||||
|
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
|
||||||
|
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
|
||||||
|
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
|
authRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, "acc")
|
||||||
|
bankRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
stakeRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
slashingRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
govRest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request makes a test LCD test request. It returns a response object and a
|
// Request makes a test LCD test request. It returns a response object and a
|
||||||
|
|
|
@ -34,7 +34,7 @@ func WriteErrorResponse(w http.ResponseWriter, status int, err string) {
|
||||||
|
|
||||||
// WriteSimulationResponse prepares and writes an HTTP
|
// WriteSimulationResponse prepares and writes an HTTP
|
||||||
// response for transactions simulations.
|
// response for transactions simulations.
|
||||||
func WriteSimulationResponse(w http.ResponseWriter, gas int64) {
|
func WriteSimulationResponse(w http.ResponseWriter, gas uint64) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas)))
|
w.Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas)))
|
||||||
}
|
}
|
||||||
|
@ -124,8 +124,8 @@ type BaseReq struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
ChainID string `json:"chain_id"`
|
ChainID string `json:"chain_id"`
|
||||||
AccountNumber int64 `json:"account_number"`
|
AccountNumber uint64 `json:"account_number"`
|
||||||
Sequence int64 `json:"sequence"`
|
Sequence uint64 `json:"sequence"`
|
||||||
Gas string `json:"gas"`
|
Gas string `json:"gas"`
|
||||||
GasAdjustment string `json:"gas_adjustment"`
|
GasAdjustment string `json:"gas_adjustment"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package utils
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
@ -71,7 +72,7 @@ func EnrichCtxWithGas(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name
|
||||||
|
|
||||||
// CalculateGas simulates the execution of a transaction and returns
|
// CalculateGas simulates the execution of a transaction and returns
|
||||||
// both the estimate obtained by the query and the adjusted amount.
|
// both the estimate obtained by the query and the adjusted amount.
|
||||||
func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *amino.Codec, txBytes []byte, adjustment float64) (estimate, adjusted int64, err error) {
|
func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *amino.Codec, txBytes []byte, adjustment float64) (estimate, adjusted uint64, err error) {
|
||||||
// run a simulation (via /app/simulate query) to
|
// run a simulation (via /app/simulate query) to
|
||||||
// estimate gas and update TxBuilder accordingly
|
// estimate gas and update TxBuilder accordingly
|
||||||
rawRes, err := queryFunc("/app/simulate", txBytes)
|
rawRes, err := queryFunc("/app/simulate", txBytes)
|
||||||
|
@ -88,7 +89,7 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *
|
||||||
|
|
||||||
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
|
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
|
||||||
// Don't perform online validation or lookups if offline is true.
|
// Don't perform online validation or lookups if offline is true.
|
||||||
func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg, offline bool) (err error) {
|
func PrintUnsignedStdTx(w io.Writer, txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg, offline bool) (err error) {
|
||||||
var stdTx auth.StdTx
|
var stdTx auth.StdTx
|
||||||
if offline {
|
if offline {
|
||||||
stdTx, err = buildUnsignedStdTxOffline(txBldr, cliCtx, msgs)
|
stdTx, err = buildUnsignedStdTxOffline(txBldr, cliCtx, msgs)
|
||||||
|
@ -100,7 +101,7 @@ func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg
|
||||||
}
|
}
|
||||||
json, err := txBldr.Codec.MarshalJSON(stdTx)
|
json, err := txBldr.Codec.MarshalJSON(stdTx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
fmt.Printf("%s\n", json)
|
fmt.Fprintf(w, "%s\n", json)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -152,7 +153,7 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
|
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
|
||||||
func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (estimated, adjusted int64, err error) {
|
func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (estimated, adjusted uint64, err error) {
|
||||||
txBytes, err := txBldr.BuildWithPubKey(name, msgs)
|
txBytes, err := txBldr.BuildWithPubKey(name, msgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -161,11 +162,11 @@ func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name stri
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
|
func adjustGasEstimate(estimate uint64, adjustment float64) uint64 {
|
||||||
return int64(adjustment * float64(estimate))
|
return uint64(adjustment * float64(estimate))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseQueryResponse(cdc *amino.Codec, rawRes []byte) (int64, error) {
|
func parseQueryResponse(cdc *amino.Codec, rawRes []byte) (uint64, error) {
|
||||||
var simulationResult sdk.Result
|
var simulationResult sdk.Result
|
||||||
if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &simulationResult); err != nil {
|
if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &simulationResult); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|
|
@ -14,16 +14,16 @@ func TestParseQueryResponse(t *testing.T) {
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: 10})
|
sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: 10})
|
||||||
gas, err := parseQueryResponse(cdc, sdkResBytes)
|
gas, err := parseQueryResponse(cdc, sdkResBytes)
|
||||||
assert.Equal(t, gas, int64(10))
|
assert.Equal(t, gas, uint64(10))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
gas, err = parseQueryResponse(cdc, []byte("fuzzy"))
|
gas, err = parseQueryResponse(cdc, []byte("fuzzy"))
|
||||||
assert.Equal(t, gas, int64(0))
|
assert.Equal(t, gas, uint64(0))
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalculateGas(t *testing.T) {
|
func TestCalculateGas(t *testing.T) {
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
makeQueryFunc := func(gasUsed int64, wantErr bool) func(string, common.HexBytes) ([]byte, error) {
|
makeQueryFunc := func(gasUsed uint64, wantErr bool) func(string, common.HexBytes) ([]byte, error) {
|
||||||
return func(string, common.HexBytes) ([]byte, error) {
|
return func(string, common.HexBytes) ([]byte, error) {
|
||||||
if wantErr {
|
if wantErr {
|
||||||
return nil, errors.New("")
|
return nil, errors.New("")
|
||||||
|
@ -32,15 +32,15 @@ func TestCalculateGas(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
queryFuncGasUsed int64
|
queryFuncGasUsed uint64
|
||||||
queryFuncWantErr bool
|
queryFuncWantErr bool
|
||||||
adjustment float64
|
adjustment float64
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
wantEstimate int64
|
wantEstimate uint64
|
||||||
wantAdjusted int64
|
wantAdjusted uint64
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"error", args{0, true, 1.2}, 0, 0, true},
|
{"error", args{0, true, 1.2}, 0, 0, true},
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -22,7 +21,6 @@ import (
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -113,7 +111,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
||||||
app.cdc,
|
app.cdc,
|
||||||
app.keyStake, app.tkeyStake,
|
app.keyStake, app.tkeyStake,
|
||||||
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
|
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
|
||||||
app.RegisterCodespace(stake.DefaultCodespace),
|
stake.DefaultCodespace,
|
||||||
)
|
)
|
||||||
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
|
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
|
||||||
app.paramsKeeper.Subspace(mint.DefaultParamspace),
|
app.paramsKeeper.Subspace(mint.DefaultParamspace),
|
||||||
|
@ -124,19 +122,19 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
||||||
app.keyDistr,
|
app.keyDistr,
|
||||||
app.paramsKeeper.Subspace(distr.DefaultParamspace),
|
app.paramsKeeper.Subspace(distr.DefaultParamspace),
|
||||||
app.bankKeeper, &stakeKeeper, app.feeCollectionKeeper,
|
app.bankKeeper, &stakeKeeper, app.feeCollectionKeeper,
|
||||||
app.RegisterCodespace(stake.DefaultCodespace),
|
distr.DefaultCodespace,
|
||||||
)
|
)
|
||||||
app.slashingKeeper = slashing.NewKeeper(
|
app.slashingKeeper = slashing.NewKeeper(
|
||||||
app.cdc,
|
app.cdc,
|
||||||
app.keySlashing,
|
app.keySlashing,
|
||||||
&stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
|
&stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
|
||||||
app.RegisterCodespace(slashing.DefaultCodespace),
|
slashing.DefaultCodespace,
|
||||||
)
|
)
|
||||||
app.govKeeper = gov.NewKeeper(
|
app.govKeeper = gov.NewKeeper(
|
||||||
app.cdc,
|
app.cdc,
|
||||||
app.keyGov,
|
app.keyGov,
|
||||||
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakeKeeper,
|
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakeKeeper,
|
||||||
app.RegisterCodespace(gov.DefaultCodespace),
|
gov.DefaultCodespace,
|
||||||
)
|
)
|
||||||
|
|
||||||
// register the staking hooks
|
// register the staking hooks
|
||||||
|
@ -218,18 +216,8 @@ func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// custom logic for gaia initialization
|
// initialize store from a genesis state
|
||||||
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisState) []abci.ValidatorUpdate {
|
||||||
stateJSON := req.AppStateBytes
|
|
||||||
// TODO is this now the whole genesis file?
|
|
||||||
|
|
||||||
var genesisState GenesisState
|
|
||||||
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
|
|
||||||
if err != nil {
|
|
||||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
|
||||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort by account number to maintain consistency
|
// sort by account number to maintain consistency
|
||||||
sort.Slice(genesisState.Accounts, func(i, j int) bool {
|
sort.Slice(genesisState.Accounts, func(i, j int) bool {
|
||||||
return genesisState.Accounts[i].AccountNumber < genesisState.Accounts[j].AccountNumber
|
return genesisState.Accounts[i].AccountNumber < genesisState.Accounts[j].AccountNumber
|
||||||
|
@ -276,6 +264,22 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
||||||
|
|
||||||
validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||||
}
|
}
|
||||||
|
return validators
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom logic for gaia initialization
|
||||||
|
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||||
|
stateJSON := req.AppStateBytes
|
||||||
|
// TODO is this now the whole genesis file?
|
||||||
|
|
||||||
|
var genesisState GenesisState
|
||||||
|
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
|
||||||
|
if err != nil {
|
||||||
|
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||||
|
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
validators := app.initFromGenesisState(ctx, genesisState)
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if len(req.Validators) > 0 {
|
if len(req.Validators) > 0 {
|
||||||
|
@ -292,40 +296,14 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assert runtime invariants
|
||||||
|
app.assertRuntimeInvariants()
|
||||||
|
|
||||||
return abci.ResponseInitChain{
|
return abci.ResponseInitChain{
|
||||||
Validators: validators,
|
Validators: validators,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// export the state of gaia for a genesis file
|
|
||||||
func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
|
||||||
ctx := app.NewContext(true, abci.Header{})
|
|
||||||
|
|
||||||
// iterate to get the accounts
|
|
||||||
accounts := []GenesisAccount{}
|
|
||||||
appendAccount := func(acc auth.Account) (stop bool) {
|
|
||||||
account := NewGenesisAccountI(acc)
|
|
||||||
accounts = append(accounts, account)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
app.accountKeeper.IterateAccounts(ctx, appendAccount)
|
|
||||||
genState := NewGenesisState(
|
|
||||||
accounts,
|
|
||||||
auth.ExportGenesis(ctx, app.feeCollectionKeeper),
|
|
||||||
stake.ExportGenesis(ctx, app.stakeKeeper),
|
|
||||||
mint.ExportGenesis(ctx, app.mintKeeper),
|
|
||||||
distr.ExportGenesis(ctx, app.distrKeeper),
|
|
||||||
gov.ExportGenesis(ctx, app.govKeeper),
|
|
||||||
slashing.ExportGenesis(ctx, app.slashingKeeper),
|
|
||||||
)
|
|
||||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
validators = stake.WriteValidators(ctx, app.stakeKeeper)
|
|
||||||
return appState, validators, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// load a particular height
|
// load a particular height
|
||||||
func (app *GaiaApp) LoadHeight(height int64) error {
|
func (app *GaiaApp) LoadHeight(height int64) error {
|
||||||
return app.LoadVersion(height, app.keyMain)
|
return app.LoadVersion(height, app.keyMain)
|
||||||
|
|
|
@ -49,6 +49,6 @@ func TestGaiadExport(t *testing.T) {
|
||||||
|
|
||||||
// Making a new app object with the db, so that initchain hasn't been called
|
// Making a new app object with the db, so that initchain hasn't been called
|
||||||
newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil)
|
newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil)
|
||||||
_, _, err := newGapp.ExportAppStateAndValidators()
|
_, _, err := newGapp.ExportAppStateAndValidators(false)
|
||||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
|
stake "github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// export the state of gaia for a genesis file
|
||||||
|
func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool) (
|
||||||
|
appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||||
|
|
||||||
|
// as if they could withdraw from the start of the next block
|
||||||
|
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
|
||||||
|
|
||||||
|
if forZeroHeight {
|
||||||
|
app.prepForZeroHeightGenesis(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate to get the accounts
|
||||||
|
accounts := []GenesisAccount{}
|
||||||
|
appendAccount := func(acc auth.Account) (stop bool) {
|
||||||
|
account := NewGenesisAccountI(acc)
|
||||||
|
accounts = append(accounts, account)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
app.accountKeeper.IterateAccounts(ctx, appendAccount)
|
||||||
|
|
||||||
|
genState := NewGenesisState(
|
||||||
|
accounts,
|
||||||
|
auth.ExportGenesis(ctx, app.feeCollectionKeeper),
|
||||||
|
stake.ExportGenesis(ctx, app.stakeKeeper),
|
||||||
|
mint.ExportGenesis(ctx, app.mintKeeper),
|
||||||
|
distr.ExportGenesis(ctx, app.distrKeeper),
|
||||||
|
gov.ExportGenesis(ctx, app.govKeeper),
|
||||||
|
slashing.ExportGenesis(ctx, app.slashingKeeper),
|
||||||
|
)
|
||||||
|
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
validators = stake.WriteValidators(ctx, app.stakeKeeper)
|
||||||
|
return appState, validators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare for fresh start at zero height
|
||||||
|
func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context) {
|
||||||
|
|
||||||
|
/* TODO XXX check some invariants */
|
||||||
|
|
||||||
|
height := ctx.BlockHeight()
|
||||||
|
|
||||||
|
valAccum := sdk.ZeroDec()
|
||||||
|
vdiIter := func(_ int64, vdi distr.ValidatorDistInfo) bool {
|
||||||
|
lastValPower := app.stakeKeeper.GetLastValidatorPower(ctx, vdi.OperatorAddr)
|
||||||
|
valAccum = valAccum.Add(vdi.GetValAccum(height, sdk.NewDecFromInt(lastValPower)))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
app.distrKeeper.IterateValidatorDistInfos(ctx, vdiIter)
|
||||||
|
|
||||||
|
lastTotalPower := sdk.NewDecFromInt(app.stakeKeeper.GetLastTotalPower(ctx))
|
||||||
|
totalAccum := app.distrKeeper.GetFeePool(ctx).GetTotalValAccum(height, lastTotalPower)
|
||||||
|
|
||||||
|
if !totalAccum.Equal(valAccum) {
|
||||||
|
panic(fmt.Errorf("validator accum invariance: \n\tfee pool totalAccum: %v"+
|
||||||
|
"\n\tvalidator accum \t%v\n", totalAccum.String(), valAccum.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("accum invariant ok!\n")
|
||||||
|
|
||||||
|
/* END TODO XXX */
|
||||||
|
|
||||||
|
/* Handle fee distribution state. */
|
||||||
|
|
||||||
|
// withdraw all delegator & validator rewards
|
||||||
|
vdiIter = func(_ int64, valInfo distr.ValidatorDistInfo) (stop bool) {
|
||||||
|
err := app.distrKeeper.WithdrawValidatorRewardsAll(ctx, valInfo.OperatorAddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
app.distrKeeper.IterateValidatorDistInfos(ctx, vdiIter)
|
||||||
|
|
||||||
|
ddiIter := func(_ int64, distInfo distr.DelegationDistInfo) (stop bool) {
|
||||||
|
err := app.distrKeeper.WithdrawDelegationReward(
|
||||||
|
ctx, distInfo.DelegatorAddr, distInfo.ValOperatorAddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
app.distrKeeper.IterateDelegationDistInfos(ctx, ddiIter)
|
||||||
|
|
||||||
|
// delete all distribution infos
|
||||||
|
// these will be recreated in InitGenesis
|
||||||
|
app.distrKeeper.RemoveValidatorDistInfos(ctx)
|
||||||
|
app.distrKeeper.RemoveDelegationDistInfos(ctx)
|
||||||
|
|
||||||
|
// assert that the fee pool is empty
|
||||||
|
feePool := app.distrKeeper.GetFeePool(ctx)
|
||||||
|
if !feePool.TotalValAccum.Accum.IsZero() {
|
||||||
|
panic("unexpected leftover validator accum")
|
||||||
|
}
|
||||||
|
bondDenom := app.stakeKeeper.GetParams(ctx).BondDenom
|
||||||
|
if !feePool.ValPool.AmountOf(bondDenom).IsZero() {
|
||||||
|
panic(fmt.Sprintf("unexpected leftover validator pool coins: %v",
|
||||||
|
feePool.ValPool.AmountOf(bondDenom).String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset fee pool height, save fee pool
|
||||||
|
feePool.TotalValAccum.UpdateHeight = 0
|
||||||
|
app.distrKeeper.SetFeePool(ctx, feePool)
|
||||||
|
|
||||||
|
/* Handle stake state. */
|
||||||
|
|
||||||
|
// iterate through validators by power descending, reset bond height, update bond intra-tx counter
|
||||||
|
store := ctx.KVStore(app.keyStake)
|
||||||
|
iter := sdk.KVStoreReversePrefixIterator(store, stake.ValidatorsByPowerIndexKey)
|
||||||
|
counter := int16(0)
|
||||||
|
for ; iter.Valid(); iter.Next() {
|
||||||
|
addr := sdk.ValAddress(iter.Value())
|
||||||
|
validator, found := app.stakeKeeper.GetValidator(ctx, addr)
|
||||||
|
if !found {
|
||||||
|
panic("expected validator, not found")
|
||||||
|
}
|
||||||
|
validator.BondHeight = 0
|
||||||
|
validator.BondIntraTxCounter = counter
|
||||||
|
validator.UnbondingHeight = 0
|
||||||
|
app.stakeKeeper.SetValidator(ctx, validator)
|
||||||
|
counter++
|
||||||
|
}
|
||||||
|
iter.Close()
|
||||||
|
|
||||||
|
/* Handle slashing state. */
|
||||||
|
|
||||||
|
// we have to clear the slashing periods, since they reference heights
|
||||||
|
app.slashingKeeper.DeleteValidatorSlashingPeriods(ctx)
|
||||||
|
|
||||||
|
// reset start height on signing infos
|
||||||
|
app.slashingKeeper.IterateValidatorSigningInfos(ctx, func(addr sdk.ConsAddress, info slashing.ValidatorSigningInfo) (stop bool) {
|
||||||
|
info.StartHeight = 0
|
||||||
|
app.slashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
|
@ -41,8 +41,10 @@ type GenesisState struct {
|
||||||
GenTxs []json.RawMessage `json:"gentxs"`
|
GenTxs []json.RawMessage `json:"gentxs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, stakeData stake.GenesisState, mintData mint.GenesisState,
|
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
|
||||||
distrData distr.GenesisState, govData gov.GenesisState, slashingData slashing.GenesisState) GenesisState {
|
stakeData stake.GenesisState, mintData mint.GenesisState,
|
||||||
|
distrData distr.GenesisState, govData gov.GenesisState,
|
||||||
|
slashingData slashing.GenesisState) GenesisState {
|
||||||
|
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Accounts: accounts,
|
Accounts: accounts,
|
||||||
|
@ -59,8 +61,8 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, stak
|
||||||
type GenesisAccount struct {
|
type GenesisAccount struct {
|
||||||
Address sdk.AccAddress `json:"address"`
|
Address sdk.AccAddress `json:"address"`
|
||||||
Coins sdk.Coins `json:"coins"`
|
Coins sdk.Coins `json:"coins"`
|
||||||
Sequence int64 `json:"sequence_number"`
|
Sequence uint64 `json:"sequence_number"`
|
||||||
AccountNumber int64 `json:"account_number"`
|
AccountNumber uint64 `json:"account_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||||
|
@ -91,7 +93,6 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Create the core parameters for genesis initialization for gaia
|
// Create the core parameters for genesis initialization for gaia
|
||||||
// note that the pubkey input is this machines pubkey
|
// note that the pubkey input is this machines pubkey
|
||||||
func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||||
|
@ -261,7 +262,7 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm
|
||||||
"account %v not in genesis.json: %+v", addr, addrMap)
|
"account %v not in genesis.json: %+v", addr, addrMap)
|
||||||
}
|
}
|
||||||
if acc.Coins.AmountOf(msg.Delegation.Denom).LT(msg.Delegation.Amount) {
|
if acc.Coins.AmountOf(msg.Delegation.Denom).LT(msg.Delegation.Amount) {
|
||||||
err = fmt.Errorf("insufficient fund for the delegation: %s < %s",
|
err = fmt.Errorf("insufficient fund for the delegation: %v < %v",
|
||||||
acc.Coins.AmountOf(msg.Delegation.Denom), msg.Delegation.Amount)
|
acc.Coins.AmountOf(msg.Delegation.Denom), msg.Delegation.Amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,11 +280,13 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm
|
||||||
|
|
||||||
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
|
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
|
||||||
accAuth := auth.NewBaseAccountWithAddress(addr)
|
accAuth := auth.NewBaseAccountWithAddress(addr)
|
||||||
coins :=sdk.Coins{
|
coins := sdk.Coins{
|
||||||
{"fooToken", sdk.NewInt(1000)},
|
sdk.NewCoin("fooToken", sdk.NewInt(1000)),
|
||||||
{bondDenom, freeFermionsAcc},
|
sdk.NewCoin(bondDenom, freeFermionsAcc),
|
||||||
}
|
}
|
||||||
|
|
||||||
coins.Sort()
|
coins.Sort()
|
||||||
|
|
||||||
accAuth.Coins = coins
|
accAuth.Coins = coins
|
||||||
return NewGenesisAccount(&accAuth)
|
return NewGenesisAccount(&accAuth)
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,11 +59,13 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
if numInitiallyBonded > numAccs {
|
if numInitiallyBonded > numAccs {
|
||||||
numInitiallyBonded = numAccs
|
numInitiallyBonded = numAccs
|
||||||
}
|
}
|
||||||
fmt.Printf("Selected randomly generated parameters for simulated genesis: {amount of steak per account: %v, initially bonded validators: %v}\n", amount, numInitiallyBonded)
|
fmt.Printf("Selected randomly generated parameters for simulated genesis:\n"+
|
||||||
|
"\t{amount of steak per account: %v, initially bonded validators: %v}\n",
|
||||||
|
amount, numInitiallyBonded)
|
||||||
|
|
||||||
// Randomly generate some genesis accounts
|
// Randomly generate some genesis accounts
|
||||||
for _, acc := range accs {
|
for _, acc := range accs {
|
||||||
coins := sdk.Coins{sdk.Coin{stakeTypes.DefaultBondDenom, sdk.NewInt(amount)}}
|
coins := sdk.Coins{sdk.NewCoin(stakeTypes.DefaultBondDenom, sdk.NewInt(amount))}
|
||||||
genesisAccounts = append(genesisAccounts, GenesisAccount{
|
genesisAccounts = append(genesisAccounts, GenesisAccount{
|
||||||
Address: acc.Address,
|
Address: acc.Address,
|
||||||
Coins: coins,
|
Coins: coins,
|
||||||
|
@ -86,7 +88,8 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
GovernancePenalty: sdk.NewDecWithPrec(1, 2),
|
GovernancePenalty: sdk.NewDecWithPrec(1, 2),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fmt.Printf("Selected randomly generated governance parameters: %+v\n", govGenesis)
|
fmt.Printf("Selected randomly generated governance parameters:\n\t%+v\n", govGenesis)
|
||||||
|
|
||||||
stakeGenesis := stake.GenesisState{
|
stakeGenesis := stake.GenesisState{
|
||||||
Pool: stake.InitialPool(),
|
Pool: stake.InitialPool(),
|
||||||
Params: stake.Params{
|
Params: stake.Params{
|
||||||
|
@ -95,7 +98,8 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
BondDenom: stakeTypes.DefaultBondDenom,
|
BondDenom: stakeTypes.DefaultBondDenom,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fmt.Printf("Selected randomly generated staking parameters: %+v\n", stakeGenesis)
|
fmt.Printf("Selected randomly generated staking parameters:\n\t%+v\n", stakeGenesis)
|
||||||
|
|
||||||
slashingGenesis := slashing.GenesisState{
|
slashingGenesis := slashing.GenesisState{
|
||||||
Params: slashing.Params{
|
Params: slashing.Params{
|
||||||
MaxEvidenceAge: stakeGenesis.Params.UnbondingTime,
|
MaxEvidenceAge: stakeGenesis.Params.UnbondingTime,
|
||||||
|
@ -107,21 +111,21 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(200) + 1))),
|
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(200) + 1))),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fmt.Printf("Selected randomly generated slashing parameters: %+v\n", slashingGenesis)
|
fmt.Printf("Selected randomly generated slashing parameters:\n\t%+v\n", slashingGenesis)
|
||||||
|
|
||||||
mintGenesis := mint.GenesisState{
|
mintGenesis := mint.GenesisState{
|
||||||
Minter: mint.Minter{
|
Minter: mint.InitialMinter(
|
||||||
InflationLastTime: time.Unix(0, 0),
|
sdk.NewDecWithPrec(int64(r.Intn(99)), 2)),
|
||||||
Inflation: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
Params: mint.NewParams(
|
||||||
},
|
stakeTypes.DefaultBondDenom,
|
||||||
Params: mint.Params{
|
sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
||||||
MintDenom: stakeTypes.DefaultBondDenom,
|
sdk.NewDecWithPrec(20, 2),
|
||||||
InflationRateChange: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
sdk.NewDecWithPrec(7, 2),
|
||||||
InflationMax: sdk.NewDecWithPrec(20, 2),
|
sdk.NewDecWithPrec(67, 2),
|
||||||
InflationMin: sdk.NewDecWithPrec(7, 2),
|
uint64(60*60*8766/5)),
|
||||||
GoalBonded: sdk.NewDecWithPrec(67, 2),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
fmt.Printf("Selected randomly generated minting parameters: %v\n", mintGenesis)
|
fmt.Printf("Selected randomly generated minting parameters:\n\t%+v\n", mintGenesis)
|
||||||
|
|
||||||
var validators []stake.Validator
|
var validators []stake.Validator
|
||||||
var delegations []stake.Delegation
|
var delegations []stake.Delegation
|
||||||
|
|
||||||
|
@ -133,7 +137,7 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
validator := stake.NewValidator(valAddr, accs[i].PubKey, stake.Description{})
|
validator := stake.NewValidator(valAddr, accs[i].PubKey, stake.Description{})
|
||||||
validator.Tokens = sdk.NewDec(amount)
|
validator.Tokens = sdk.NewDec(amount)
|
||||||
validator.DelegatorShares = sdk.NewDec(amount)
|
validator.DelegatorShares = sdk.NewDec(amount)
|
||||||
delegation := stake.Delegation{accs[i].Address, valAddr, sdk.NewDec(amount), 0}
|
delegation := stake.Delegation{accs[i].Address, valAddr, sdk.NewDec(amount)}
|
||||||
validators = append(validators, validator)
|
validators = append(validators, validator)
|
||||||
delegations = append(delegations, delegation)
|
delegations = append(delegations, delegation)
|
||||||
}
|
}
|
||||||
|
@ -206,7 +210,7 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
// TODO parameterize numbers, save for a later PR
|
// TODO parameterize numbers, save for a later PR
|
||||||
err := simulation.SimulateFromSeed(
|
_, err := simulation.SimulateFromSeed(
|
||||||
b, app.BaseApp, appStateFn, seed,
|
b, app.BaseApp, appStateFn, seed,
|
||||||
testAndRunTxs(app),
|
testAndRunTxs(app),
|
||||||
[]simulation.RandSetup{},
|
[]simulation.RandSetup{},
|
||||||
|
@ -249,7 +253,7 @@ func TestFullGaiaSimulation(t *testing.T) {
|
||||||
require.Equal(t, "GaiaApp", app.Name())
|
require.Equal(t, "GaiaApp", app.Name())
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
err := simulation.SimulateFromSeed(
|
_, err := simulation.SimulateFromSeed(
|
||||||
t, app.BaseApp, appStateFn, seed,
|
t, app.BaseApp, appStateFn, seed,
|
||||||
testAndRunTxs(app),
|
testAndRunTxs(app),
|
||||||
[]simulation.RandSetup{},
|
[]simulation.RandSetup{},
|
||||||
|
@ -291,7 +295,7 @@ func TestGaiaImportExport(t *testing.T) {
|
||||||
require.Equal(t, "GaiaApp", app.Name())
|
require.Equal(t, "GaiaApp", app.Name())
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
err := simulation.SimulateFromSeed(
|
_, err := simulation.SimulateFromSeed(
|
||||||
t, app.BaseApp, appStateFn, seed,
|
t, app.BaseApp, appStateFn, seed,
|
||||||
testAndRunTxs(app),
|
testAndRunTxs(app),
|
||||||
[]simulation.RandSetup{},
|
[]simulation.RandSetup{},
|
||||||
|
@ -311,7 +315,7 @@ func TestGaiaImportExport(t *testing.T) {
|
||||||
|
|
||||||
fmt.Printf("Exporting genesis...\n")
|
fmt.Printf("Exporting genesis...\n")
|
||||||
|
|
||||||
appState, _, err := app.ExportAppStateAndValidators()
|
appState, _, err := app.ExportAppStateAndValidators(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -326,15 +330,16 @@ func TestGaiaImportExport(t *testing.T) {
|
||||||
}()
|
}()
|
||||||
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil)
|
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil)
|
||||||
require.Equal(t, "GaiaApp", newApp.Name())
|
require.Equal(t, "GaiaApp", newApp.Name())
|
||||||
request := abci.RequestInitChain{
|
var genesisState GenesisState
|
||||||
AppStateBytes: appState,
|
err = app.cdc.UnmarshalJSON(appState, &genesisState)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
newApp.InitChain(request)
|
ctxB := newApp.NewContext(true, abci.Header{})
|
||||||
newApp.Commit()
|
newApp.initFromGenesisState(ctxB, genesisState)
|
||||||
|
|
||||||
fmt.Printf("Comparing stores...\n")
|
fmt.Printf("Comparing stores...\n")
|
||||||
ctxA := app.NewContext(true, abci.Header{})
|
ctxA := app.NewContext(true, abci.Header{})
|
||||||
ctxB := newApp.NewContext(true, abci.Header{})
|
|
||||||
type StoreKeysPrefixes struct {
|
type StoreKeysPrefixes struct {
|
||||||
A sdk.StoreKey
|
A sdk.StoreKey
|
||||||
B sdk.StoreKey
|
B sdk.StoreKey
|
||||||
|
@ -365,6 +370,87 @@ func TestGaiaImportExport(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGaiaSimulationAfterImport(t *testing.T) {
|
||||||
|
if !enabled {
|
||||||
|
t.Skip("Skipping Gaia simulation after import")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup Gaia application
|
||||||
|
var logger log.Logger
|
||||||
|
if verbose {
|
||||||
|
logger = log.TestingLogger()
|
||||||
|
} else {
|
||||||
|
logger = log.NewNopLogger()
|
||||||
|
}
|
||||||
|
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
|
||||||
|
db, _ := dbm.NewGoLevelDB("Simulation", dir)
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
os.RemoveAll(dir)
|
||||||
|
}()
|
||||||
|
app := NewGaiaApp(logger, db, nil)
|
||||||
|
require.Equal(t, "GaiaApp", app.Name())
|
||||||
|
|
||||||
|
// Run randomized simulation
|
||||||
|
stopEarly, err := simulation.SimulateFromSeed(
|
||||||
|
t, app.BaseApp, appStateFn, seed,
|
||||||
|
testAndRunTxs(app),
|
||||||
|
[]simulation.RandSetup{},
|
||||||
|
invariants(app),
|
||||||
|
numBlocks,
|
||||||
|
blockSize,
|
||||||
|
commit,
|
||||||
|
)
|
||||||
|
if commit {
|
||||||
|
// for memdb:
|
||||||
|
// fmt.Println("Database Size", db.Stats()["database.size"])
|
||||||
|
fmt.Println("GoLevelDB Stats")
|
||||||
|
fmt.Println(db.Stats()["leveldb.stats"])
|
||||||
|
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
|
||||||
|
}
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
if stopEarly {
|
||||||
|
// we can't export or import a zero-validator genesis
|
||||||
|
fmt.Printf("We can't export or import a zero-validator genesis, exiting test...\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Exporting genesis...\n")
|
||||||
|
|
||||||
|
appState, _, err := app.ExportAppStateAndValidators(true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Importing genesis...\n")
|
||||||
|
|
||||||
|
newDir, _ := ioutil.TempDir("", "goleveldb-gaia-sim-2")
|
||||||
|
newDB, _ := dbm.NewGoLevelDB("Simulation-2", dir)
|
||||||
|
defer func() {
|
||||||
|
newDB.Close()
|
||||||
|
os.RemoveAll(newDir)
|
||||||
|
}()
|
||||||
|
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil)
|
||||||
|
require.Equal(t, "GaiaApp", newApp.Name())
|
||||||
|
newApp.InitChain(abci.RequestInitChain{
|
||||||
|
AppStateBytes: appState,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Run randomized simulation on imported app
|
||||||
|
_, err = simulation.SimulateFromSeed(
|
||||||
|
t, newApp.BaseApp, appStateFn, seed,
|
||||||
|
testAndRunTxs(newApp),
|
||||||
|
[]simulation.RandSetup{},
|
||||||
|
invariants(newApp),
|
||||||
|
numBlocks,
|
||||||
|
blockSize,
|
||||||
|
commit,
|
||||||
|
)
|
||||||
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
// TODO: Make another test for the fuzzer itself, which just has noOp txs
|
||||||
// and doesn't depend on gaia
|
// and doesn't depend on gaia
|
||||||
func TestAppStateDeterminism(t *testing.T) {
|
func TestAppStateDeterminism(t *testing.T) {
|
||||||
|
|
|
@ -370,7 +370,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
require.Equal(t, " 1 - Test", proposalsQuery)
|
require.Equal(t, " 1 - Test", proposalsQuery)
|
||||||
|
|
||||||
deposit := executeGetDeposit(t,
|
deposit := executeGetDeposit(t,
|
||||||
fmt.Sprintf("gaiacli query gov deposit --proposal-id=1 --depositer=%s --output=json %v",
|
fmt.Sprintf("gaiacli query gov deposit --proposal-id=1 --depositor=%s --output=json %v",
|
||||||
fooAddr, flags))
|
fooAddr, flags))
|
||||||
require.Equal(t, int64(5), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
require.Equal(t, int64(5), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||||
|
|
||||||
|
@ -399,7 +399,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
require.Equal(t, int64(15), deposits[0].Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
require.Equal(t, int64(15), deposits[0].Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||||
|
|
||||||
deposit = executeGetDeposit(t,
|
deposit = executeGetDeposit(t,
|
||||||
fmt.Sprintf("gaiacli query gov deposit --proposal-id=1 --depositer=%s --output=json %v",
|
fmt.Sprintf("gaiacli query gov deposit --proposal-id=1 --depositor=%s --output=json %v",
|
||||||
fooAddr, flags))
|
fooAddr, flags))
|
||||||
require.Equal(t, int64(15), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
require.Equal(t, int64(15), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||||
|
|
||||||
|
@ -480,7 +480,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
msg := unmarshalStdTx(t, stdout)
|
msg := unmarshalStdTx(t, stdout)
|
||||||
require.Equal(t, msg.Fee.Gas, int64(client.DefaultGasLimit))
|
require.Equal(t, msg.Fee.Gas, uint64(client.DefaultGasLimit))
|
||||||
require.Equal(t, len(msg.Msgs), 1)
|
require.Equal(t, len(msg.Msgs), 1)
|
||||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||||
|
|
||||||
|
@ -491,7 +491,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
require.Empty(t, stderr)
|
require.Empty(t, stderr)
|
||||||
msg = unmarshalStdTx(t, stdout)
|
msg = unmarshalStdTx(t, stdout)
|
||||||
require.Equal(t, msg.Fee.Gas, int64(100))
|
require.Equal(t, msg.Fee.Gas, uint64(100))
|
||||||
require.Equal(t, len(msg.Msgs), 1)
|
require.Equal(t, len(msg.Msgs), 1)
|
||||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||||
|
|
||||||
|
@ -542,16 +542,19 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
||||||
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||||
"gaiacli tx broadcast %v --json %v", flags, signedTxFile.Name()))
|
"gaiacli tx broadcast %v --json %v", flags, signedTxFile.Name()))
|
||||||
require.True(t, success)
|
require.True(t, success)
|
||||||
|
|
||||||
var result struct {
|
var result struct {
|
||||||
Response abci.ResponseDeliverTx
|
Response abci.ResponseDeliverTx
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Nil(t, app.MakeCodec().UnmarshalJSON([]byte(stdout), &result))
|
require.Nil(t, app.MakeCodec().UnmarshalJSON([]byte(stdout), &result))
|
||||||
require.Equal(t, msg.Fee.Gas, result.Response.GasUsed)
|
require.Equal(t, msg.Fee.Gas, uint64(result.Response.GasUsed))
|
||||||
require.Equal(t, msg.Fee.Gas, result.Response.GasWanted)
|
require.Equal(t, msg.Fee.Gas, uint64(result.Response.GasWanted))
|
||||||
tests.WaitForNextNBlocksTM(2, port)
|
tests.WaitForNextNBlocksTM(2, port)
|
||||||
|
|
||||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
||||||
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||||
|
|
||||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||||
}
|
}
|
||||||
|
@ -608,10 +611,11 @@ func getTestingHomeDirs() (string, string) {
|
||||||
|
|
||||||
func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
|
func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
|
||||||
tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe-reset-all", gaiadHome), "")
|
tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe-reset-all", gaiadHome), "")
|
||||||
|
os.RemoveAll(filepath.Join(gaiadHome, "config", "gentx"))
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
executeWriteCheckErr(t, fmt.Sprintf("gaiacli keys add --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
||||||
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
executeWriteCheckErr(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
||||||
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf(
|
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf(
|
||||||
"gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
"gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||||
chainID = executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome))
|
chainID = executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome))
|
||||||
|
@ -625,10 +629,10 @@ func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
genDoc.AppState = appStateJSON
|
genDoc.AppState = appStateJSON
|
||||||
genDoc.SaveAs(genFile)
|
genDoc.SaveAs(genFile)
|
||||||
executeWrite(t, fmt.Sprintf(
|
executeWriteCheckErr(t, fmt.Sprintf(
|
||||||
"gaiad gentx --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome),
|
"gaiad gentx --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome),
|
||||||
app.DefaultKeyPass)
|
app.DefaultKeyPass)
|
||||||
executeWrite(t, fmt.Sprintf("gaiad collect-gentxs --home=%s", gaiadHome), app.DefaultKeyPass)
|
executeWriteCheckErr(t, fmt.Sprintf("gaiad collect-gentxs --home=%s", gaiadHome), app.DefaultKeyPass)
|
||||||
// get a free port, also setup some common flags
|
// get a free port, also setup some common flags
|
||||||
servAddr, port, err = server.FreeTCPAddr()
|
servAddr, port, err = server.FreeTCPAddr()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -664,6 +668,10 @@ func readGenesisFile(t *testing.T, genFile string) types.GenesisDoc {
|
||||||
//___________________________________________________________________________________
|
//___________________________________________________________________________________
|
||||||
// executors
|
// executors
|
||||||
|
|
||||||
|
func executeWriteCheckErr(t *testing.T, cmdStr string, writes ...string) {
|
||||||
|
require.True(t, executeWrite(t, cmdStr, writes...))
|
||||||
|
}
|
||||||
|
|
||||||
func executeWrite(t *testing.T, cmdStr string, writes ...string) (exitSuccess bool) {
|
func executeWrite(t *testing.T, cmdStr string, writes ...string) (exitSuccess bool) {
|
||||||
exitSuccess, _, _ = executeWriteRetStdStreams(t, cmdStr, writes...)
|
exitSuccess, _, _ = executeWriteRetStdStreams(t, cmdStr, writes...)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,64 +1,98 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
"github.com/rakyll/statik/fs"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
amino "github.com/tendermint/go-amino"
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/version"
|
"github.com/cosmos/cosmos-sdk/version"
|
||||||
|
|
||||||
|
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||||
|
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||||
|
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||||
|
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
||||||
|
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||||
|
|
||||||
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||||
|
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||||
|
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
|
||||||
|
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
|
||||||
|
slashingClient "github.com/cosmos/cosmos-sdk/x/slashing/client"
|
||||||
|
stakeClient "github.com/cosmos/cosmos-sdk/x/stake/client"
|
||||||
|
|
||||||
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
|
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
storeAcc = "acc"
|
storeAcc = "acc"
|
||||||
storeGov = "gov"
|
storeGov = "gov"
|
||||||
storeSlashing = "slashing"
|
storeSlashing = "slashing"
|
||||||
storeStake = "stake"
|
storeStake = "stake"
|
||||||
queryRouteStake = "stake"
|
storeDist = "distr"
|
||||||
)
|
|
||||||
|
|
||||||
// rootCmd is the entry point for this binary
|
|
||||||
var (
|
|
||||||
rootCmd = &cobra.Command{
|
|
||||||
Use: "gaiacli",
|
|
||||||
Short: "Command line interface for interacting with gaiad",
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// Configure cobra to sort commands
|
||||||
cobra.EnableCommandSorting = false
|
cobra.EnableCommandSorting = false
|
||||||
|
|
||||||
|
// Instantiate the codec for the command line application
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
|
||||||
|
// Read in the configuration file for the sdk
|
||||||
config := sdk.GetConfig()
|
config := sdk.GetConfig()
|
||||||
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
||||||
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
|
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
|
||||||
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
|
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
|
||||||
config.Seal()
|
config.Seal()
|
||||||
|
|
||||||
|
// Create a new RestServer instance to serve the light client routes
|
||||||
|
rs := lcd.NewRestServer(cdc)
|
||||||
|
|
||||||
|
// registerRoutes registers the routes on the rest server
|
||||||
|
registerRoutes(rs)
|
||||||
|
|
||||||
// TODO: setup keybase, viper object, etc. to be passed into
|
// TODO: setup keybase, viper object, etc. to be passed into
|
||||||
// the below functions and eliminate global vars, like we do
|
// the below functions and eliminate global vars, like we do
|
||||||
// with the cdc
|
// with the cdc
|
||||||
|
|
||||||
|
// Module clients hold cli commnads (tx,query) and lcd routes
|
||||||
|
// TODO: Make the lcd command take a list of ModuleClient
|
||||||
|
mc := []sdk.ModuleClients{
|
||||||
|
govClient.NewModuleClient(storeGov, cdc),
|
||||||
|
distClient.NewModuleClient(storeDist, cdc),
|
||||||
|
stakeClient.NewModuleClient(storeStake, cdc),
|
||||||
|
slashingClient.NewModuleClient(storeSlashing, cdc),
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCmd := &cobra.Command{
|
||||||
|
Use: "gaiacli",
|
||||||
|
Short: "Command line interface for interacting with gaiad",
|
||||||
|
}
|
||||||
|
|
||||||
// Construct Root Command
|
// Construct Root Command
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
rpc.InitClientCommand(),
|
rpc.InitClientCommand(),
|
||||||
rpc.StatusCommand(),
|
rpc.StatusCommand(),
|
||||||
client.ConfigCmd(),
|
client.ConfigCmd(),
|
||||||
queryCmd(cdc),
|
queryCmd(cdc, mc),
|
||||||
txCmd(cdc),
|
txCmd(cdc, mc),
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
lcd.ServeCommand(cdc),
|
rs.ServeCommand(),
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
keys.Commands(),
|
keys.Commands(),
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
|
@ -74,9 +108,77 @@ func main() {
|
||||||
|
|
||||||
err = executor.Execute()
|
err = executor.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// handle with #870
|
fmt.Printf("Failed executing CLI command: %s, exiting...\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
|
||||||
|
queryCmd := &cobra.Command{
|
||||||
|
Use: "query",
|
||||||
|
Aliases: []string{"q"},
|
||||||
|
Short: "Querying subcommands",
|
||||||
|
}
|
||||||
|
|
||||||
|
queryCmd.AddCommand(
|
||||||
|
rpc.ValidatorCommand(),
|
||||||
|
rpc.BlockCommand(),
|
||||||
|
tx.SearchTxCmd(cdc),
|
||||||
|
tx.QueryTxCmd(cdc),
|
||||||
|
client.LineBreak,
|
||||||
|
authcmd.GetAccountCmd(storeAcc, cdc),
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, m := range mc {
|
||||||
|
queryCmd.AddCommand(m.GetQueryCmd())
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func txCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
|
||||||
|
txCmd := &cobra.Command{
|
||||||
|
Use: "tx",
|
||||||
|
Short: "Transactions subcommands",
|
||||||
|
}
|
||||||
|
|
||||||
|
txCmd.AddCommand(
|
||||||
|
bankcmd.SendTxCmd(cdc),
|
||||||
|
client.LineBreak,
|
||||||
|
authcmd.GetSignCommand(cdc),
|
||||||
|
bankcmd.GetBroadcastCommand(cdc),
|
||||||
|
client.LineBreak,
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, m := range mc {
|
||||||
|
txCmd.AddCommand(m.GetTxCmd())
|
||||||
|
}
|
||||||
|
|
||||||
|
return txCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerRoutes registers the routes from the different modules for the LCD.
|
||||||
|
// NOTE: details on the routes added for each module are in the module documentation
|
||||||
|
// NOTE: If making updates here you also need to update the test helper in client/lcd/test_helper.go
|
||||||
|
func registerRoutes(rs *lcd.RestServer) {
|
||||||
|
registerSwaggerUI(rs)
|
||||||
|
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
|
||||||
|
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
|
||||||
|
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
|
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, storeAcc)
|
||||||
|
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
stake.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
gov.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerSwaggerUI(rs *lcd.RestServer) {
|
||||||
|
statikFS, err := fs.New()
|
||||||
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
staticServer := http.FileServer(statikFS)
|
||||||
|
rs.Mux.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer))
|
||||||
}
|
}
|
||||||
|
|
||||||
func initConfig(cmd *cobra.Command) error {
|
func initConfig(cmd *cobra.Command) error {
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
||||||
govcmd "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
|
|
||||||
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
|
|
||||||
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
|
||||||
amino "github.com/tendermint/go-amino"
|
|
||||||
)
|
|
||||||
|
|
||||||
func queryCmd(cdc *amino.Codec) *cobra.Command {
|
|
||||||
//Add query commands
|
|
||||||
queryCmd := &cobra.Command{
|
|
||||||
Use: "query",
|
|
||||||
Aliases: []string{"q"},
|
|
||||||
Short: "Querying subcommands",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group staking queries under a subcommand
|
|
||||||
stakeQueryCmd := &cobra.Command{
|
|
||||||
Use: "stake",
|
|
||||||
Short: "Querying commands for the staking module",
|
|
||||||
}
|
|
||||||
|
|
||||||
stakeQueryCmd.AddCommand(client.GetCommands(
|
|
||||||
stakecmd.GetCmdQueryDelegation(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryDelegations(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryUnbondingDelegation(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryUnbondingDelegations(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryRedelegation(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryRedelegations(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryValidator(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryValidators(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryValidatorDelegations(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryValidatorUnbondingDelegations(queryRouteStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryValidatorRedelegations(queryRouteStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryParams(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdQueryPool(storeStake, cdc))...)
|
|
||||||
|
|
||||||
// Group gov queries under a subcommand
|
|
||||||
govQueryCmd := &cobra.Command{
|
|
||||||
Use: "gov",
|
|
||||||
Short: "Querying commands for the governance module",
|
|
||||||
}
|
|
||||||
|
|
||||||
govQueryCmd.AddCommand(client.GetCommands(
|
|
||||||
govcmd.GetCmdQueryProposal(storeGov, cdc),
|
|
||||||
govcmd.GetCmdQueryProposals(storeGov, cdc),
|
|
||||||
govcmd.GetCmdQueryVote(storeGov, cdc),
|
|
||||||
govcmd.GetCmdQueryVotes(storeGov, cdc),
|
|
||||||
govcmd.GetCmdQueryParams(storeGov, cdc),
|
|
||||||
govcmd.GetCmdQueryDeposit(storeGov, cdc),
|
|
||||||
govcmd.GetCmdQueryDeposits(storeGov, cdc))...)
|
|
||||||
|
|
||||||
// Group slashing queries under a subcommand
|
|
||||||
slashingQueryCmd := &cobra.Command{
|
|
||||||
Use: "slashing",
|
|
||||||
Short: "Querying commands for the slashing module",
|
|
||||||
}
|
|
||||||
|
|
||||||
slashingQueryCmd.AddCommand(client.GetCommands(
|
|
||||||
slashingcmd.GetCmdQuerySigningInfo(storeSlashing, cdc))...)
|
|
||||||
|
|
||||||
// Query commcmmand structure
|
|
||||||
queryCmd.AddCommand(
|
|
||||||
rpc.BlockCommand(),
|
|
||||||
rpc.ValidatorCommand(),
|
|
||||||
tx.SearchTxCmd(cdc),
|
|
||||||
tx.QueryTxCmd(cdc),
|
|
||||||
client.LineBreak,
|
|
||||||
client.GetCommands(authcmd.GetAccountCmd(storeAcc, cdc, authcmd.GetAccountDecoder(cdc)))[0],
|
|
||||||
stakeQueryCmd,
|
|
||||||
govQueryCmd,
|
|
||||||
slashingQueryCmd,
|
|
||||||
)
|
|
||||||
|
|
||||||
return queryCmd
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
||||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
|
||||||
distrcmd "github.com/cosmos/cosmos-sdk/x/distribution/client/cli"
|
|
||||||
govcmd "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
|
|
||||||
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
|
|
||||||
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
|
||||||
amino "github.com/tendermint/go-amino"
|
|
||||||
)
|
|
||||||
|
|
||||||
func txCmd(cdc *amino.Codec) *cobra.Command {
|
|
||||||
//Add transaction generation commands
|
|
||||||
txCmd := &cobra.Command{
|
|
||||||
Use: "tx",
|
|
||||||
Short: "Transactions subcommands",
|
|
||||||
}
|
|
||||||
|
|
||||||
stakeTxCmd := &cobra.Command{
|
|
||||||
Use: "stake",
|
|
||||||
Short: "Staking transaction subcommands",
|
|
||||||
}
|
|
||||||
|
|
||||||
stakeTxCmd.AddCommand(client.PostCommands(
|
|
||||||
stakecmd.GetCmdCreateValidator(cdc),
|
|
||||||
stakecmd.GetCmdEditValidator(cdc),
|
|
||||||
stakecmd.GetCmdDelegate(cdc),
|
|
||||||
stakecmd.GetCmdRedelegate(storeStake, cdc),
|
|
||||||
stakecmd.GetCmdUnbond(storeStake, cdc),
|
|
||||||
)...)
|
|
||||||
|
|
||||||
distTxCmd := &cobra.Command{
|
|
||||||
Use: "dist",
|
|
||||||
Short: "Distribution transactions subcommands",
|
|
||||||
}
|
|
||||||
|
|
||||||
distTxCmd.AddCommand(client.PostCommands(
|
|
||||||
distrcmd.GetCmdWithdrawRewards(cdc),
|
|
||||||
distrcmd.GetCmdSetWithdrawAddr(cdc),
|
|
||||||
)...)
|
|
||||||
|
|
||||||
govTxCmd := &cobra.Command{
|
|
||||||
Use: "gov",
|
|
||||||
Short: "Governance transactions subcommands",
|
|
||||||
}
|
|
||||||
|
|
||||||
govTxCmd.AddCommand(client.PostCommands(
|
|
||||||
govcmd.GetCmdDeposit(cdc),
|
|
||||||
govcmd.GetCmdVote(cdc),
|
|
||||||
govcmd.GetCmdSubmitProposal(cdc),
|
|
||||||
)...)
|
|
||||||
|
|
||||||
slashingTxCmd := &cobra.Command{
|
|
||||||
Use: "slashing",
|
|
||||||
Short: "Slashing transactions subcommands",
|
|
||||||
}
|
|
||||||
|
|
||||||
slashingTxCmd.AddCommand(client.PostCommands(
|
|
||||||
slashingcmd.GetCmdUnjail(cdc),
|
|
||||||
)...)
|
|
||||||
|
|
||||||
txCmd.AddCommand(
|
|
||||||
//Add auth and bank commands
|
|
||||||
client.PostCommands(
|
|
||||||
bankcmd.SendTxCmd(cdc),
|
|
||||||
bankcmd.GetBroadcastCommand(cdc),
|
|
||||||
authcmd.GetSignCommand(cdc, authcmd.GetAccountDecoder(cdc)),
|
|
||||||
)...)
|
|
||||||
|
|
||||||
txCmd.AddCommand(
|
|
||||||
client.LineBreak,
|
|
||||||
stakeTxCmd,
|
|
||||||
distTxCmd,
|
|
||||||
govTxCmd,
|
|
||||||
slashingTxCmd,
|
|
||||||
)
|
|
||||||
|
|
||||||
return txCmd
|
|
||||||
}
|
|
|
@ -62,7 +62,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportAppStateAndTMValidators(
|
func exportAppStateAndTMValidators(
|
||||||
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64,
|
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool,
|
||||||
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
gApp := app.NewGaiaApp(logger, db, traceStore)
|
gApp := app.NewGaiaApp(logger, db, traceStore)
|
||||||
if height != -1 {
|
if height != -1 {
|
||||||
|
@ -71,5 +71,5 @@ func exportAppStateAndTMValidators(
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gApp.ExportAppStateAndValidators()
|
return gApp.ExportAppStateAndValidators(forZeroHeight)
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,8 +175,8 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp
|
||||||
// add handlers
|
// add handlers
|
||||||
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
|
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
|
||||||
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
|
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
|
||||||
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace), app.RegisterCodespace(stake.DefaultCodespace))
|
app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.tkeyStake, app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace), stake.DefaultCodespace)
|
||||||
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), app.RegisterCodespace(slashing.DefaultCodespace))
|
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), slashing.DefaultCodespace)
|
||||||
|
|
||||||
// register message routes
|
// register message routes
|
||||||
app.Router().
|
app.Router().
|
||||||
|
|
|
@ -25,14 +25,14 @@ func TestAddGenesisAccount(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"valid account",
|
"valid account",
|
||||||
args{
|
args{
|
||||||
app.GenesisState{},
|
app.GenesisState{},
|
||||||
addr1,
|
addr1,
|
||||||
sdk.Coins{},
|
sdk.Coins{},
|
||||||
},
|
},
|
||||||
false},
|
false},
|
||||||
{"dup account", args{
|
{"dup account", args{
|
||||||
app.GenesisState{Accounts: []app.GenesisAccount{app.GenesisAccount{Address:addr1}}},
|
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
|
||||||
addr1,
|
addr1,
|
||||||
sdk.Coins{}}, true},
|
sdk.Coins{}}, true},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,32 @@
|
||||||
package init
|
package init
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
"github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
||||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||||
"github.com/tendermint/tendermint/libs/common"
|
"github.com/tendermint/tendermint/libs/common"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -66,7 +73,9 @@ following delegation and commission default parameters:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = kb.Get(viper.GetString(client.FlagName)); err != nil {
|
|
||||||
|
name := viper.GetString(client.FlagName)
|
||||||
|
if _, err := kb.Get(name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,27 +88,40 @@ following delegation and commission default parameters:
|
||||||
}
|
}
|
||||||
// Run gaiad tx create-validator
|
// Run gaiad tx create-validator
|
||||||
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey)
|
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey)
|
||||||
createValidatorCmd := cli.GetCmdCreateValidator(cdc)
|
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||||
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
w, err := ioutil.TempFile("", "gentx")
|
cliCtx, txBldr, msg, err := cli.BuildCreateValidatorMsg(cliCtx, txBldr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
unsignedGenTxFilename := w.Name()
|
|
||||||
defer os.Remove(unsignedGenTxFilename)
|
|
||||||
os.Stdout = w
|
|
||||||
if err = createValidatorCmd.RunE(nil, args); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
prepareFlagsForTxSign()
|
// write the unsigned transaction to the buffer
|
||||||
signCmd := authcmd.GetSignCommand(cdc, authcmd.GetAccountDecoder(cdc))
|
w := bytes.NewBuffer([]byte{})
|
||||||
if w, err = prepareOutputFile(config.RootDir, nodeID); err != nil {
|
if err := utils.PrintUnsignedStdTx(w, txBldr, cliCtx, []sdk.Msg{msg}, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
os.Stdout = w
|
|
||||||
return signCmd.RunE(nil, []string{unsignedGenTxFilename})
|
// read the transaction
|
||||||
|
stdTx, err := readUnsignedGenTxFile(cdc, w)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign the transaction and write it to the output file
|
||||||
|
signedTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, false, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
outputDocument, err := makeOutputFilepath(config.RootDir, nodeID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := writeSignedGenTx(cdc, outputDocument, signedTx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "Genesis transaction written to %q\n", outputDocument)
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,15 +162,35 @@ func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip, chainID st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareFlagsForTxSign() {
|
func makeOutputFilepath(rootDir, nodeID string) (string, error) {
|
||||||
viper.Set("offline", true)
|
writePath := filepath.Join(rootDir, "config", "gentx")
|
||||||
|
if err := common.EnsureDir(writePath, 0700); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareOutputFile(rootDir, nodeID string) (w *os.File, err error) {
|
func readUnsignedGenTxFile(cdc *codec.Codec, r io.Reader) (auth.StdTx, error) {
|
||||||
writePath := filepath.Join(rootDir, "config", "gentx")
|
var stdTx auth.StdTx
|
||||||
if err = common.EnsureDir(writePath, 0700); err != nil {
|
bytes, err := ioutil.ReadAll(r)
|
||||||
return
|
if err != nil {
|
||||||
|
return stdTx, err
|
||||||
}
|
}
|
||||||
filename := filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID))
|
err = cdc.UnmarshalJSON(bytes, &stdTx)
|
||||||
return os.Create(filename)
|
return stdTx, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint: errcheck
|
||||||
|
func writeSignedGenTx(cdc *codec.Codec, outputDocument string, tx auth.StdTx) error {
|
||||||
|
outputFile, err := os.OpenFile(outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer outputFile.Close()
|
||||||
|
json, err := cdc.MarshalJSON(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = fmt.Fprintf(outputFile, "%s\n", json)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ services:
|
||||||
- "26656-26657:26656-26657"
|
- "26656-26657:26656-26657"
|
||||||
environment:
|
environment:
|
||||||
- ID=0
|
- ID=0
|
||||||
- LOG=$${LOG:-gaiad.log}
|
- LOG=${LOG:-gaiad.log}
|
||||||
volumes:
|
volumes:
|
||||||
- ./build:/gaiad:Z
|
- ./build:/gaiad:Z
|
||||||
networks:
|
networks:
|
||||||
|
@ -22,7 +22,7 @@ services:
|
||||||
- "26659-26660:26656-26657"
|
- "26659-26660:26656-26657"
|
||||||
environment:
|
environment:
|
||||||
- ID=1
|
- ID=1
|
||||||
- LOG=$${LOG:-gaiad.log}
|
- LOG=${LOG:-gaiad.log}
|
||||||
volumes:
|
volumes:
|
||||||
- ./build:/gaiad:Z
|
- ./build:/gaiad:Z
|
||||||
networks:
|
networks:
|
||||||
|
@ -34,7 +34,7 @@ services:
|
||||||
image: "tendermint/gaiadnode"
|
image: "tendermint/gaiadnode"
|
||||||
environment:
|
environment:
|
||||||
- ID=2
|
- ID=2
|
||||||
- LOG=$${LOG:-gaiad.log}
|
- LOG=${LOG:-gaiad.log}
|
||||||
ports:
|
ports:
|
||||||
- "26661-26662:26656-26657"
|
- "26661-26662:26656-26657"
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -48,7 +48,7 @@ services:
|
||||||
image: "tendermint/gaiadnode"
|
image: "tendermint/gaiadnode"
|
||||||
environment:
|
environment:
|
||||||
- ID=3
|
- ID=3
|
||||||
- LOG=$${LOG:-gaiad.log}
|
- LOG=${LOG:-gaiad.log}
|
||||||
ports:
|
ports:
|
||||||
- "26663-26664:26656-26657"
|
- "26663-26664:26656-26657"
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -52,11 +52,11 @@ type Account interface {
|
||||||
GetPubKey() crypto.PubKey // can return nil.
|
GetPubKey() crypto.PubKey // can return nil.
|
||||||
SetPubKey(crypto.PubKey) error
|
SetPubKey(crypto.PubKey) error
|
||||||
|
|
||||||
GetAccountNumber() int64
|
GetAccountNumber() uint64
|
||||||
SetAccountNumber(int64) error
|
SetAccountNumber(uint64) error
|
||||||
|
|
||||||
GetSequence() int64
|
GetSequence() uint64
|
||||||
SetSequence(int64) error
|
SetSequence(uint64) error
|
||||||
|
|
||||||
GetCoins() sdk.Coins
|
GetCoins() sdk.Coins
|
||||||
SetCoins(sdk.Coins) error
|
SetCoins(sdk.Coins) error
|
||||||
|
@ -79,8 +79,8 @@ type BaseAccount struct {
|
||||||
Address sdk.AccAddress `json:"address"`
|
Address sdk.AccAddress `json:"address"`
|
||||||
Coins sdk.Coins `json:"coins"`
|
Coins sdk.Coins `json:"coins"`
|
||||||
PubKey crypto.PubKey `json:"public_key"`
|
PubKey crypto.PubKey `json:"public_key"`
|
||||||
AccountNumber int64 `json:"account_number"`
|
AccountNumber uint64 `json:"account_number"`
|
||||||
Sequence int64 `json:"sequence"`
|
Sequence uint64 `json:"sequence"`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -161,8 +161,8 @@ The standard form for signatures is `StdSignature`:
|
||||||
type StdSignature struct {
|
type StdSignature struct {
|
||||||
crypto.PubKey `json:"pub_key"` // optional
|
crypto.PubKey `json:"pub_key"` // optional
|
||||||
[]byte `json:"signature"`
|
[]byte `json:"signature"`
|
||||||
AccountNumber int64 `json:"account_number"`
|
AccountNumber uint64 `json:"account_number"`
|
||||||
Sequence int64 `json:"sequence"`
|
Sequence uint64 `json:"sequence"`
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
app1Name = "App1"
|
app1Name = "App1"
|
||||||
|
bankCodespace = "BANK"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
||||||
|
@ -107,7 +108,7 @@ func handleMsgSend(key *sdk.KVStoreKey) sdk.Handler {
|
||||||
if !ok {
|
if !ok {
|
||||||
// Create custom error message and return result
|
// Create custom error message and return result
|
||||||
// Note: Using unreserved error codespace
|
// Note: Using unreserved error codespace
|
||||||
return sdk.NewError(2, 1, "MsgSend is malformed").Result()
|
return sdk.NewError(bankCodespace, 1, "MsgSend is malformed").Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the store.
|
// Load the store.
|
||||||
|
@ -137,7 +138,7 @@ func handleFrom(store sdk.KVStore, from sdk.AccAddress, amt sdk.Coins) sdk.Resul
|
||||||
accBytes := store.Get(from)
|
accBytes := store.Get(from)
|
||||||
if accBytes == nil {
|
if accBytes == nil {
|
||||||
// Account was not added to store. Return the result of the error.
|
// Account was not added to store. Return the result of the error.
|
||||||
return sdk.NewError(2, 101, "Account not added to store").Result()
|
return sdk.NewError(bankCodespace, 101, "Account not added to store").Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal the JSON account bytes.
|
// Unmarshal the JSON account bytes.
|
||||||
|
|
|
@ -126,7 +126,7 @@ func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handle
|
||||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
issueMsg, ok := msg.(MsgIssue)
|
issueMsg, ok := msg.(MsgIssue)
|
||||||
if !ok {
|
if !ok {
|
||||||
return sdk.NewError(2, 1, "MsgIssue is malformed").Result()
|
return sdk.NewError(bankCodespace, 1, "MsgIssue is malformed").Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve stores
|
// Retrieve stores
|
||||||
|
|
|
@ -20,7 +20,7 @@ func TestEncoding(t *testing.T) {
|
||||||
sendMsg := MsgSend{
|
sendMsg := MsgSend{
|
||||||
From: addr1,
|
From: addr1,
|
||||||
To: addr2,
|
To: addr2,
|
||||||
Amount: sdk.Coins{{"testCoins", sdk.NewInt(100)}},
|
Amount: sdk.Coins{sdk.NewCoin("testCoins", sdk.NewInt(100))},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct transaction
|
// Construct transaction
|
||||||
|
|
|
@ -30,7 +30,7 @@ func InitTestChain(bc *bapp.BaseApp, chainID string, addrs ...sdk.AccAddress) {
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
acc := GenesisAccount{
|
acc := GenesisAccount{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Coins: sdk.Coins{{"testCoin", sdk.NewInt(100)}},
|
Coins: sdk.Coins{sdk.NewCoin("testCoin", sdk.NewInt(100))},
|
||||||
}
|
}
|
||||||
accounts = append(accounts, &acc)
|
accounts = append(accounts, &acc)
|
||||||
}
|
}
|
||||||
|
@ -61,12 +61,12 @@ func TestBadMsg(t *testing.T) {
|
||||||
addr2 := priv2.PubKey().Address().Bytes()
|
addr2 := priv2.PubKey().Address().Bytes()
|
||||||
|
|
||||||
// Attempt to spend non-existent funds
|
// Attempt to spend non-existent funds
|
||||||
msg := GenerateSpendMsg(addr1, addr2, sdk.Coins{{"testCoin", sdk.NewInt(100)}})
|
msg := GenerateSpendMsg(addr1, addr2, sdk.Coins{sdk.NewCoin("testCoin", sdk.NewInt(100))})
|
||||||
|
|
||||||
// Construct transaction
|
// Construct transaction
|
||||||
fee := auth.StdFee{
|
fee := auth.StdFee{
|
||||||
Gas: 1000000000000000,
|
Gas: 1000000000000000,
|
||||||
Amount: sdk.Coins{{"testCoin", sdk.NewInt(0)}},
|
Amount: sdk.Coins{sdk.NewCoin("testCoin", sdk.NewInt(0))},
|
||||||
}
|
}
|
||||||
signBytes := auth.StdSignBytes("test-chain", 0, 0, fee, []sdk.Msg{msg}, "")
|
signBytes := auth.StdSignBytes("test-chain", 0, 0, fee, []sdk.Msg{msg}, "")
|
||||||
sig, err := priv1.Sign(signBytes)
|
sig, err := priv1.Sign(signBytes)
|
||||||
|
@ -108,11 +108,11 @@ func TestMsgSend(t *testing.T) {
|
||||||
InitTestChain(bc, "test-chain", addr1)
|
InitTestChain(bc, "test-chain", addr1)
|
||||||
|
|
||||||
// Send funds to addr2
|
// Send funds to addr2
|
||||||
msg := GenerateSpendMsg(addr1, addr2, sdk.Coins{{"testCoin", sdk.NewInt(100)}})
|
msg := GenerateSpendMsg(addr1, addr2, sdk.Coins{sdk.NewCoin("testCoin", sdk.NewInt(100))})
|
||||||
|
|
||||||
fee := auth.StdFee{
|
fee := auth.StdFee{
|
||||||
Gas: 1000000000000000,
|
Gas: 1000000000000000,
|
||||||
Amount: sdk.Coins{{"testCoin", sdk.NewInt(0)}},
|
Amount: sdk.Coins{sdk.NewCoin("testCoin", sdk.NewInt(0))},
|
||||||
}
|
}
|
||||||
signBytes := auth.StdSignBytes("test-chain", 0, 0, fee, []sdk.Msg{msg}, "")
|
signBytes := auth.StdSignBytes("test-chain", 0, 0, fee, []sdk.Msg{msg}, "")
|
||||||
sig, err := priv1.Sign(signBytes)
|
sig, err := priv1.Sign(signBytes)
|
||||||
|
|
|
@ -75,7 +75,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.Ba
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
|
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
|
||||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
|
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, ibc.DefaultCodespace)
|
||||||
|
|
||||||
// register message routes
|
// register message routes
|
||||||
app.Router().
|
app.Router().
|
||||||
|
|
|
@ -8,17 +8,28 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||||
"github.com/cosmos/cosmos-sdk/docs/examples/basecoin/app"
|
"github.com/cosmos/cosmos-sdk/docs/examples/basecoin/app"
|
||||||
"github.com/cosmos/cosmos-sdk/docs/examples/basecoin/types"
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/version"
|
"github.com/cosmos/cosmos-sdk/version"
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||||
|
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||||
|
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||||
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
|
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
|
||||||
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
|
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
|
||||||
|
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
|
||||||
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
||||||
|
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
storeAcc = "acc"
|
||||||
|
storeSlashing = "slashing"
|
||||||
|
storeStake = "stake"
|
||||||
|
)
|
||||||
|
|
||||||
// rootCmd is the entry point for this binary
|
// rootCmd is the entry point for this binary
|
||||||
var (
|
var (
|
||||||
rootCmd = &cobra.Command{
|
rootCmd = &cobra.Command{
|
||||||
|
@ -34,6 +45,17 @@ func main() {
|
||||||
// get the codec
|
// get the codec
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
|
|
||||||
|
// Setup certain SDK config
|
||||||
|
config := sdk.GetConfig()
|
||||||
|
config.SetBech32PrefixForAccount("baseacc", "basepub")
|
||||||
|
config.SetBech32PrefixForValidator("baseval", "basevalpub")
|
||||||
|
config.SetBech32PrefixForConsensusNode("basecons", "baseconspub")
|
||||||
|
config.Seal()
|
||||||
|
|
||||||
|
rs := lcd.NewRestServer(cdc)
|
||||||
|
|
||||||
|
registerRoutes(rs)
|
||||||
|
|
||||||
// TODO: Setup keybase, viper object, etc. to be passed into
|
// TODO: Setup keybase, viper object, etc. to be passed into
|
||||||
// the below functions and eliminate global vars, like we do
|
// the below functions and eliminate global vars, like we do
|
||||||
// with the cdc.
|
// with the cdc.
|
||||||
|
@ -50,40 +72,39 @@ func main() {
|
||||||
|
|
||||||
// add query/post commands (custom to binary)
|
// add query/post commands (custom to binary)
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.GetCommands(
|
stakecmd.GetCmdQueryValidator(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryValidator("stake", cdc),
|
stakecmd.GetCmdQueryValidators(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryValidators("stake", cdc),
|
stakecmd.GetCmdQueryValidatorUnbondingDelegations(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryValidatorUnbondingDelegations("stake", cdc),
|
stakecmd.GetCmdQueryValidatorRedelegations(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryValidatorRedelegations("stake", cdc),
|
stakecmd.GetCmdQueryDelegation(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryDelegation("stake", cdc),
|
stakecmd.GetCmdQueryDelegations(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryDelegations("stake", cdc),
|
stakecmd.GetCmdQueryPool(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryPool("stake", cdc),
|
stakecmd.GetCmdQueryParams(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryParams("stake", cdc),
|
stakecmd.GetCmdQueryUnbondingDelegation(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryUnbondingDelegation("stake", cdc),
|
stakecmd.GetCmdQueryUnbondingDelegations(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryUnbondingDelegations("stake", cdc),
|
stakecmd.GetCmdQueryRedelegation(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryRedelegation("stake", cdc),
|
stakecmd.GetCmdQueryRedelegations(storeStake, cdc),
|
||||||
stakecmd.GetCmdQueryRedelegations("stake", cdc),
|
slashingcmd.GetCmdQuerySigningInfo(storeSlashing, cdc),
|
||||||
slashingcmd.GetCmdQuerySigningInfo("slashing", cdc),
|
stakecmd.GetCmdQueryValidatorDelegations(storeStake, cdc),
|
||||||
authcmd.GetAccountCmd("acc", cdc, types.GetAccountDecoder(cdc)),
|
authcmd.GetAccountCmd(storeAcc, cdc),
|
||||||
)...)
|
)
|
||||||
|
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.PostCommands(
|
bankcmd.SendTxCmd(cdc),
|
||||||
bankcmd.SendTxCmd(cdc),
|
ibccmd.IBCTransferCmd(cdc),
|
||||||
ibccmd.IBCTransferCmd(cdc),
|
ibccmd.IBCRelayCmd(cdc),
|
||||||
ibccmd.IBCRelayCmd(cdc),
|
stakecmd.GetCmdCreateValidator(cdc),
|
||||||
stakecmd.GetCmdCreateValidator(cdc),
|
stakecmd.GetCmdEditValidator(cdc),
|
||||||
stakecmd.GetCmdEditValidator(cdc),
|
stakecmd.GetCmdDelegate(cdc),
|
||||||
stakecmd.GetCmdDelegate(cdc),
|
stakecmd.GetCmdUnbond(storeStake, cdc),
|
||||||
stakecmd.GetCmdUnbond("stake", cdc),
|
stakecmd.GetCmdRedelegate(storeStake, cdc),
|
||||||
stakecmd.GetCmdRedelegate("stake", cdc),
|
slashingcmd.GetCmdUnjail(cdc),
|
||||||
slashingcmd.GetCmdUnjail(cdc),
|
)
|
||||||
)...)
|
|
||||||
|
|
||||||
// add proxy, version and key info
|
// add proxy, version and key info
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
lcd.ServeCommand(cdc),
|
rs.ServeCommand(),
|
||||||
keys.Commands(),
|
keys.Commands(),
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
version.VersionCmd,
|
version.VersionCmd,
|
||||||
|
@ -97,3 +118,13 @@ func main() {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerRoutes(rs *lcd.RestServer) {
|
||||||
|
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
|
||||||
|
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
|
||||||
|
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
|
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, storeAcc)
|
||||||
|
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
stake.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ func newApp(logger log.Logger, db dbm.DB, storeTracer io.Writer) abci.Applicatio
|
||||||
return app.NewBasecoinApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
|
return app.NewBasecoinApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, storeTracer io.Writer, _ int64) (
|
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, storeTracer io.Writer, _ int64, _ bool) (
|
||||||
json.RawMessage, []tmtypes.GenesisValidator, error) {
|
json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
bapp := app.NewBasecoinApp(logger, db)
|
bapp := app.NewBasecoinApp(logger, db)
|
||||||
return bapp.ExportAppStateAndValidators()
|
return bapp.ExportAppStateAndValidators()
|
||||||
|
|
|
@ -83,10 +83,10 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
|
||||||
|
|
||||||
// Add handlers.
|
// Add handlers.
|
||||||
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
|
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
|
||||||
app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.bankKeeper, app.RegisterCodespace(cool.DefaultCodespace))
|
app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.bankKeeper, cool.DefaultCodespace)
|
||||||
app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.bankKeeper, app.RegisterCodespace(pow.DefaultCodespace))
|
app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.bankKeeper, pow.DefaultCodespace)
|
||||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace))
|
app.ibcMapper = ibc.NewMapper(app.cdc, app.capKeyIBCStore, ibc.DefaultCodespace)
|
||||||
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper, app.RegisterCodespace(simplestake.DefaultCodespace))
|
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper, simplestake.DefaultCodespace)
|
||||||
app.Router().
|
app.Router().
|
||||||
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
|
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
|
||||||
AddRoute("cool", cool.NewHandler(app.coolKeeper)).
|
AddRoute("cool", cool.NewHandler(app.coolKeeper)).
|
||||||
|
|
|
@ -13,11 +13,11 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/version"
|
"github.com/cosmos/cosmos-sdk/version"
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||||
|
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||||
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
|
||||||
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
|
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/app"
|
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/app"
|
||||||
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/types"
|
|
||||||
coolcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool/client/cli"
|
coolcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool/client/cli"
|
||||||
powcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/pow/client/cli"
|
powcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/pow/client/cli"
|
||||||
simplestakingcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/simplestake/client/cli"
|
simplestakingcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/simplestake/client/cli"
|
||||||
|
@ -31,6 +31,7 @@ var (
|
||||||
Use: "democli",
|
Use: "democli",
|
||||||
Short: "Democoin light-client",
|
Short: "Democoin light-client",
|
||||||
}
|
}
|
||||||
|
storeAcc = "acc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -47,6 +48,10 @@ func main() {
|
||||||
config.SetBech32PrefixForConsensusNode("democons", "democonspub")
|
config.SetBech32PrefixForConsensusNode("democons", "democonspub")
|
||||||
config.Seal()
|
config.Seal()
|
||||||
|
|
||||||
|
rs := lcd.NewRestServer(cdc)
|
||||||
|
|
||||||
|
registerRoutes(rs)
|
||||||
|
|
||||||
// TODO: setup keybase, viper object, etc. to be passed into
|
// TODO: setup keybase, viper object, etc. to be passed into
|
||||||
// the below functions and eliminate global vars, like we do
|
// the below functions and eliminate global vars, like we do
|
||||||
// with the cdc
|
// with the cdc
|
||||||
|
@ -65,20 +70,13 @@ func main() {
|
||||||
// add query/post commands (custom to binary)
|
// add query/post commands (custom to binary)
|
||||||
// start with commands common to basecoin
|
// start with commands common to basecoin
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.GetCommands(
|
authcmd.GetAccountCmd(storeAcc, cdc),
|
||||||
authcmd.GetAccountCmd("acc", cdc, types.GetAccountDecoder(cdc)),
|
)
|
||||||
)...)
|
rootCmd.AddCommand(
|
||||||
|
bankcmd.SendTxCmd(cdc),
|
||||||
|
)
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.PostCommands(
|
client.PostCommands(
|
||||||
bankcmd.SendTxCmd(cdc),
|
|
||||||
)...)
|
|
||||||
rootCmd.AddCommand(
|
|
||||||
client.PostCommands(
|
|
||||||
ibccmd.IBCTransferCmd(cdc),
|
|
||||||
)...)
|
|
||||||
rootCmd.AddCommand(
|
|
||||||
client.PostCommands(
|
|
||||||
ibccmd.IBCRelayCmd(cdc),
|
|
||||||
simplestakingcmd.BondTxCmd(cdc),
|
simplestakingcmd.BondTxCmd(cdc),
|
||||||
)...)
|
)...)
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
|
@ -96,7 +94,7 @@ func main() {
|
||||||
// add proxy, version and key info
|
// add proxy, version and key info
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
lcd.ServeCommand(cdc),
|
rs.ServeCommand(),
|
||||||
keys.Commands(),
|
keys.Commands(),
|
||||||
client.LineBreak,
|
client.LineBreak,
|
||||||
version.VersionCmd,
|
version.VersionCmd,
|
||||||
|
@ -110,3 +108,11 @@ func main() {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerRoutes(rs *lcd.RestServer) {
|
||||||
|
keys.RegisterRoutes(rs.Mux, rs.CliCtx.Indent)
|
||||||
|
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
|
||||||
|
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
|
||||||
|
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, storeAcc)
|
||||||
|
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ const (
|
||||||
flagClientHome = "home-client"
|
flagClientHome = "home-client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// coolGenAppParams sets up the app_state and appends the cool app state
|
// coolGenAppParams sets up the app_state and appends the cool app state
|
||||||
func CoolAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
func CoolAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||||
appState json.RawMessage, err error) {
|
appState json.RawMessage, err error) {
|
||||||
|
@ -129,7 +128,7 @@ func newApp(logger log.Logger, db dbm.DB, _ io.Writer) abci.Application {
|
||||||
return app.NewDemocoinApp(logger, db)
|
return app.NewDemocoinApp(logger, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, _ io.Writer, _ int64) (
|
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, _ io.Writer, _ int64, _ bool) (
|
||||||
json.RawMessage, []tmtypes.GenesisValidator, error) {
|
json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||||
dapp := app.NewDemocoinApp(logger, db)
|
dapp := app.NewDemocoinApp(logger, db)
|
||||||
return dapp.ExportAppStateAndValidators()
|
return dapp.ExportAppStateAndValidators()
|
||||||
|
|
|
@ -50,7 +50,7 @@ func getMockApp(t *testing.T) *mock.App {
|
||||||
RegisterCodec(mapp.Cdc)
|
RegisterCodec(mapp.Cdc)
|
||||||
keyCool := sdk.NewKVStoreKey("cool")
|
keyCool := sdk.NewKVStoreKey("cool")
|
||||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper)
|
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper)
|
||||||
keeper := NewKeeper(keyCool, bankKeeper, mapp.RegisterCodespace(DefaultCodespace))
|
keeper := NewKeeper(keyCool, bankKeeper, DefaultCodespace)
|
||||||
mapp.Router().AddRoute("cool", NewHandler(keeper))
|
mapp.Router().AddRoute("cool", NewHandler(keeper))
|
||||||
|
|
||||||
mapp.SetInitChainer(getInitChainer(mapp, keeper, "ice-cold"))
|
mapp.SetInitChainer(getInitChainer(mapp, keeper, "ice-cold"))
|
||||||
|
@ -88,17 +88,17 @@ func TestMsgQuiz(t *testing.T) {
|
||||||
require.Equal(t, acc1, res1)
|
require.Equal(t, acc1, res1)
|
||||||
|
|
||||||
// Set the trend, submit a really cool quiz and check for reward
|
// Set the trend, submit a really cool quiz and check for reward
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []int64{0}, []int64{0}, true, true, priv1)
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []uint64{0}, []uint64{0}, true, true, priv1)
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{1}, true, true, priv1)
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []uint64{0}, []uint64{1}, true, true, priv1)
|
||||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}})
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(69))})
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{2}, false, false, priv1) // result without reward
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []uint64{0}, []uint64{2}, false, false, priv1) // result without reward
|
||||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}})
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(69))})
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{3}, true, true, priv1)
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []uint64{0}, []uint64{3}, true, true, priv1)
|
||||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(138)}})
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(138))})
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []int64{0}, []int64{4}, true, true, priv1) // reset the trend
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []uint64{0}, []uint64{4}, true, true, priv1) // reset the trend
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{5}, false, false, priv1) // the same answer will nolonger do!
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []uint64{0}, []uint64{5}, false, false, priv1) // the same answer will nolonger do!
|
||||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(138)}})
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(138))})
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{6}, true, true, priv1) // earlier answer now relevant again
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []uint64{0}, []uint64{6}, true, true, priv1) // earlier answer now relevant again
|
||||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"badvibesonly", sdk.NewInt(69)}, {"icecold", sdk.NewInt(138)}})
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("badvibesonly", sdk.NewInt(69)), sdk.NewCoin("icecold", sdk.NewInt(138))})
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []int64{0}, []int64{7}, false, false, priv1) // expect to fail to set the trend to something which is not cool
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []uint64{0}, []uint64{7}, false, false, priv1) // expect to fail to set the trend to something which is not cool
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool"
|
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/cool"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
||||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +21,7 @@ func QuizTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||||
cliCtx := context.NewCLIContext().
|
cliCtx := context.NewCLIContext().
|
||||||
WithCodec(cdc).
|
WithCodec(cdc).
|
||||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
WithAccountDecoder(cdc)
|
||||||
|
|
||||||
from, err := cliCtx.GetFromAddress()
|
from, err := cliCtx.GetFromAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -46,7 +45,7 @@ func SetTrendTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||||
cliCtx := context.NewCLIContext().
|
cliCtx := context.NewCLIContext().
|
||||||
WithCodec(cdc).
|
WithCodec(cdc).
|
||||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
WithAccountDecoder(cdc)
|
||||||
|
|
||||||
from, err := cliCtx.GetFromAddress()
|
from, err := cliCtx.GetFromAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
// Cool errors reserve 400 ~ 499.
|
// Cool errors reserve 400 ~ 499.
|
||||||
const (
|
const (
|
||||||
DefaultCodespace sdk.CodespaceType = 6
|
DefaultCodespace sdk.CodespaceType = "cool"
|
||||||
|
|
||||||
// Cool module reserves error 400-499 lawl
|
// Cool module reserves error 400-499 lawl
|
||||||
CodeIncorrectCoolAnswer sdk.CodeType = 400
|
CodeIncorrectCoolAnswer sdk.CodeType = 400
|
||||||
|
|
|
@ -94,7 +94,7 @@ func (keeper Keeper) Handle(h Handler, ctx sdk.Context, o Msg, codespace sdk.Cod
|
||||||
err := h(cctx, payload)
|
err := h(cctx, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.Result{
|
return sdk.Result{
|
||||||
Code: sdk.ABCICodeOK,
|
Code: sdk.CodeOK,
|
||||||
Log: err.ABCILog(),
|
Log: err.ABCILog(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ func getMockApp(t *testing.T) *mock.App {
|
||||||
keyPOW := sdk.NewKVStoreKey("pow")
|
keyPOW := sdk.NewKVStoreKey("pow")
|
||||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper)
|
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper)
|
||||||
config := Config{"pow", 1}
|
config := Config{"pow", 1}
|
||||||
keeper := NewKeeper(keyPOW, config, bankKeeper, mapp.RegisterCodespace(DefaultCodespace))
|
keeper := NewKeeper(keyPOW, config, bankKeeper, DefaultCodespace)
|
||||||
mapp.Router().AddRoute("pow", keeper.Handler)
|
mapp.Router().AddRoute("pow", keeper.Handler)
|
||||||
|
|
||||||
mapp.SetInitChainer(getInitChainer(mapp, keeper))
|
mapp.SetInitChainer(getInitChainer(mapp, keeper))
|
||||||
|
@ -74,13 +74,13 @@ func TestMsgMine(t *testing.T) {
|
||||||
|
|
||||||
// Mine and check for reward
|
// Mine and check for reward
|
||||||
mineMsg1 := GenerateMsgMine(addr1, 1, 2)
|
mineMsg1 := GenerateMsgMine(addr1, 1, 2)
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []int64{0}, []int64{0}, true, true, priv1)
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []uint64{0}, []uint64{0}, true, true, priv1)
|
||||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(1)}})
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("pow", sdk.NewInt(1))})
|
||||||
// Mine again and check for reward
|
// Mine again and check for reward
|
||||||
mineMsg2 := GenerateMsgMine(addr1, 2, 3)
|
mineMsg2 := GenerateMsgMine(addr1, 2, 3)
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, true, true, priv1)
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []uint64{0}, []uint64{1}, true, true, priv1)
|
||||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}})
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("pow", sdk.NewInt(2))})
|
||||||
// Mine again - should be invalid
|
// Mine again - should be invalid
|
||||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, false, false, priv1)
|
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []uint64{0}, []uint64{1}, false, false, priv1)
|
||||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}})
|
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("pow", sdk.NewInt(2))})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/pow"
|
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/pow"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
||||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -24,7 +23,7 @@ func MineCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||||
cliCtx := context.NewCLIContext().
|
cliCtx := context.NewCLIContext().
|
||||||
WithCodec(cdc).
|
WithCodec(cdc).
|
||||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
WithAccountDecoder(cdc)
|
||||||
|
|
||||||
from, err := cliCtx.GetFromAddress()
|
from, err := cliCtx.GetFromAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -9,7 +9,7 @@ type CodeType = sdk.CodeType
|
||||||
|
|
||||||
// POW errors reserve 200 ~ 299
|
// POW errors reserve 200 ~ 299
|
||||||
const (
|
const (
|
||||||
DefaultCodespace sdk.CodespaceType = 5
|
DefaultCodespace sdk.CodespaceType = "pow"
|
||||||
CodeInvalidDifficulty CodeType = 201
|
CodeInvalidDifficulty CodeType = 201
|
||||||
CodeNonexistentDifficulty CodeType = 202
|
CodeNonexistentDifficulty CodeType = 202
|
||||||
CodeNonexistentReward CodeType = 203
|
CodeNonexistentReward CodeType = 203
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/simplestake"
|
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/simplestake"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
||||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -32,7 +31,7 @@ func BondTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||||
cliCtx := context.NewCLIContext().
|
cliCtx := context.NewCLIContext().
|
||||||
WithCodec(cdc).
|
WithCodec(cdc).
|
||||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
WithAccountDecoder(cdc)
|
||||||
|
|
||||||
from, err := cliCtx.GetFromAddress()
|
from, err := cliCtx.GetFromAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
// simple stake errors reserve 300 ~ 399.
|
// simple stake errors reserve 300 ~ 399.
|
||||||
const (
|
const (
|
||||||
DefaultCodespace sdk.CodespaceType = 4
|
DefaultCodespace sdk.CodespaceType = moduleName
|
||||||
|
|
||||||
// simplestake errors reserve 300 - 399.
|
// simplestake errors reserve 300 - 399.
|
||||||
CodeEmptyValidator sdk.CodeType = 300
|
CodeEmptyValidator sdk.CodeType = 300
|
||||||
|
|
|
@ -22,12 +22,12 @@ func handleMsgBond() sdk.Result {
|
||||||
// Removed ValidatorSet from result because it does not get used.
|
// Removed ValidatorSet from result because it does not get used.
|
||||||
// TODO: Implement correct bond/unbond handling
|
// TODO: Implement correct bond/unbond handling
|
||||||
return sdk.Result{
|
return sdk.Result{
|
||||||
Code: sdk.ABCICodeOK,
|
Code: sdk.CodeOK,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMsgUnbond() sdk.Result {
|
func handleMsgUnbond() sdk.Result {
|
||||||
return sdk.Result{
|
return sdk.Result{
|
||||||
Code: sdk.ABCICodeOK,
|
Code: sdk.CodeOK,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,12 @@ There are three types of key representations that are used:
|
||||||
- Derived from account keys generated by `gaiacli keys add`
|
- Derived from account keys generated by `gaiacli keys add`
|
||||||
- Used to receive funds
|
- Used to receive funds
|
||||||
- e.g. `cosmos15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc`
|
- e.g. `cosmos15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc`
|
||||||
|
|
||||||
* `cosmosvaloper`
|
* `cosmosvaloper`
|
||||||
* Used to associate a validator to it's operator
|
- Used to associate a validator to it's operator
|
||||||
* Used to invoke staking commands
|
- Used to invoke staking commands
|
||||||
* e.g. `cosmosvaloper1carzvgq3e6y3z5kz5y6gxp3wpy3qdrv928vyah`
|
- e.g. `cosmosvaloper1carzvgq3e6y3z5kz5y6gxp3wpy3qdrv928vyah`
|
||||||
|
|
||||||
- `cosmospub`
|
- `cosmospub`
|
||||||
- Derived from account keys generated by `gaiacli keys add`
|
- Derived from account keys generated by `gaiacli keys add`
|
||||||
- e.g. `cosmospub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm`
|
- e.g. `cosmospub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm`
|
||||||
|
@ -72,7 +74,7 @@ View the validator pubkey for your node by typing:
|
||||||
gaiad tendermint show-validator
|
gaiad tendermint show-validator
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that this is the Tendermint signing key, *not* the operator key you will use in delegation transactions.
|
Note that this is the Tendermint signing key, _not_ the operator key you will use in delegation transactions.
|
||||||
|
|
||||||
::: danger Warning
|
::: danger Warning
|
||||||
We strongly recommend _NOT_ using the same passphrase for multiple keys. The Tendermint team and the Interchain Foundation will not be responsible for the loss of funds.
|
We strongly recommend _NOT_ using the same passphrase for multiple keys. The Tendermint team and the Interchain Foundation will not be responsible for the loss of funds.
|
||||||
|
@ -211,7 +213,7 @@ gaiacli query stake validator <account_cosmosval>
|
||||||
|
|
||||||
#### Bond Tokens
|
#### Bond Tokens
|
||||||
|
|
||||||
On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond tokens to a testnet validator (*i.e.* delegate):
|
On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond tokens to a testnet validator (_i.e._ delegate):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gaiacli tx stake delegate \
|
gaiacli tx stake delegate \
|
||||||
|
@ -304,7 +306,7 @@ gaiacli tx stake redelegate \
|
||||||
--chain-id=<chain_id>
|
--chain-id=<chain_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
Here you can also redelegate a specific `shares-amount` or a `shares-fraction` with the corresponding flags.
|
Here you can also redelegate a specific `shares-amount` or a `shares-fraction` with the corresponding flags.
|
||||||
|
|
||||||
The redelegation will be automatically completed when the unbonding period has passed.
|
The redelegation will be automatically completed when the unbonding period has passed.
|
||||||
|
|
||||||
|
@ -367,6 +369,7 @@ With the `pool` command you will get the values for:
|
||||||
##### Query Delegations To Validator
|
##### Query Delegations To Validator
|
||||||
|
|
||||||
You can also query all of the delegations to a particular validator:
|
You can also query all of the delegations to a particular validator:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gaiacli query delegations-to <account_cosmosval>
|
gaiacli query delegations-to <account_cosmosval>
|
||||||
```
|
```
|
||||||
|
@ -418,7 +421,7 @@ Or query all available proposals:
|
||||||
gaiacli query gov proposals
|
gaiacli query gov proposals
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also query proposals filtered by `voter` or `depositer` by using the corresponding flags.
|
You can also query proposals filtered by `voter` or `depositor` by using the corresponding flags.
|
||||||
|
|
||||||
#### Increase deposit
|
#### Increase deposit
|
||||||
|
|
||||||
|
@ -447,7 +450,7 @@ You can also query a deposit submitted by a specific address:
|
||||||
```bash
|
```bash
|
||||||
gaiacli query gov deposit \
|
gaiacli query gov deposit \
|
||||||
--proposal-id=<proposal_id> \
|
--proposal-id=<proposal_id> \
|
||||||
--depositer=<account_cosmos>
|
--depositor=<account_cosmos>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Vote on a proposal
|
#### Vote on a proposal
|
||||||
|
|
|
@ -142,7 +142,13 @@ gaiad export > [filename].json
|
||||||
You can also export state from a particular height (at the end of processing the block of that height):
|
You can also export state from a particular height (at the end of processing the block of that height):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gaiad export --height=[height] > [filename].json
|
gaiad export --height [height] > [filename].json
|
||||||
|
```
|
||||||
|
|
||||||
|
If you plan to start a new network from the exported state, export with the `--for-zero-height` flag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiad export --height [height] --for-zero-height > [filename].json
|
||||||
```
|
```
|
||||||
|
|
||||||
## Upgrade to Validator Node
|
## Upgrade to Validator Node
|
||||||
|
|
|
@ -63,7 +63,7 @@ principle:
|
||||||
type AppAccount struct {...}
|
type AppAccount struct {...}
|
||||||
var account := &AppAccount{
|
var account := &AppAccount{
|
||||||
Address: pub.Address(),
|
Address: pub.Address(),
|
||||||
Coins: sdk.Coins{{"ATM", 100}},
|
Coins: sdk.Coins{sdk.NewInt64Coin("ATM", 100)},
|
||||||
}
|
}
|
||||||
var sumValue := externalModule.ComputeSumValue(account)
|
var sumValue := externalModule.ComputeSumValue(account)
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,13 +1,124 @@
|
||||||
# baseApp
|
# BaseApp
|
||||||
|
|
||||||
`baseApp` requires stores to be mounted via capabilities keys - handlers can only access stores they're given the key to. The `baseApp` ensures all stores are properly loaded, cached, and committed. One mounted store is considered the "main" - it holds the latest block header, from which we can find and load the most recent state.
|
The BaseApp defines the foundational implementation for a basic ABCI application
|
||||||
|
so that your Cosmos-SDK application can communicate with an underlying
|
||||||
|
Tendermint node.
|
||||||
|
|
||||||
`baseApp` distinguishes between two handler types: `AnteHandler` and `MsgHandler`. Whilst the former is a global validity check that applies to all transactions from all modules, i.e. it checks nonces and whether balances are sufficient to pay fees, validates signatures and ensures that transactions don't carry too many signatures, the latter is the full state transition function.
|
The BaseApp is composed of many internal components. Some of the most important
|
||||||
During CheckTx the state transition function is only applied to the checkTxState and should return
|
include the `CommitMultiStore` and its internal state. The internal state is
|
||||||
before any expensive state transitions are run (this is up to each developer). It also needs to return the estimated
|
essentially two sub-states, both of which are used for transaction execution
|
||||||
gas cost.
|
during different phases, `CheckTx` and `DeliverTx` respectively. During block
|
||||||
|
commitment, only the `DeliverTx` is persisted.
|
||||||
|
|
||||||
During DeliverTx the state transition function is applied to the blockchain state and the transactions
|
The BaseApp requires stores to be mounted via capabilities keys - handlers can
|
||||||
need to be fully executed.
|
only access stores they're given the key to. The `baseApp` ensures all stores are
|
||||||
|
properly loaded, cached, and committed. One mounted store is considered the
|
||||||
|
"main" - it holds the latest block header, from which we can find and load the
|
||||||
|
most recent state.
|
||||||
|
|
||||||
BaseApp is responsible for managing the context passed into handlers - it makes the block header available and provides the right stores for CheckTx and DeliverTx. BaseApp is completely agnostic to serialization formats.
|
The BaseApp distinguishes between two handler types - the `AnteHandler` and the
|
||||||
|
`MsgHandler`. The former is a global validity check (checking nonces, sigs and
|
||||||
|
sufficient balances to pay fees, e.g. things that apply to all transaction from
|
||||||
|
all modules), the later is the full state transition function.
|
||||||
|
|
||||||
|
During `CheckTx` the state transition function is only applied to the `checkTxState`
|
||||||
|
and should return before any expensive state transitions are run
|
||||||
|
(this is up to each developer). It also needs to return the estimated gas cost.
|
||||||
|
|
||||||
|
During `DeliverTx` the state transition function is applied to the blockchain
|
||||||
|
state and the transactions need to be fully executed.
|
||||||
|
|
||||||
|
The BaseApp is responsible for managing the context passed into handlers -
|
||||||
|
it makes the block header available and provides the right stores for `CheckTx`
|
||||||
|
and `DeliverTx`. BaseApp is completely agnostic to serialization formats.
|
||||||
|
|
||||||
|
## Transaction Life Cycle
|
||||||
|
|
||||||
|
During the execution of a transaction, it may pass through both `CheckTx` and
|
||||||
|
`DeliverTx` as defined in the ABCI specification. `CheckTx` is executed by the
|
||||||
|
proposing validator and is used for the Tendermint mempool for all full nodes.
|
||||||
|
|
||||||
|
Both `CheckTx` and `DeliverTx` execute the application's AnteHandler (if
|
||||||
|
defined), where the AnteHandler is responsible for pre-message validation
|
||||||
|
checks such as account and signature validation, fee deduction and collection,
|
||||||
|
and incrementing sequence numbers.
|
||||||
|
|
||||||
|
### CheckTx
|
||||||
|
|
||||||
|
During the execution of `CheckTx`, only the AnteHandler is executed.
|
||||||
|
|
||||||
|
State transitions due to the AnteHandler are persisted between subsequent calls
|
||||||
|
of `CheckTx` in the check-tx state, unless the AnteHandler fails and aborts.
|
||||||
|
|
||||||
|
### DeliverTx
|
||||||
|
|
||||||
|
During the execution of `DeliverTx`, the AnteHandler and Handler is executed.
|
||||||
|
|
||||||
|
The transaction execution during `DeliverTx` operates in a similar fashion to
|
||||||
|
`CheckTx`. However, state transitions that occur during the AnteHandler are
|
||||||
|
persisted even when the following Handler processing logic fails.
|
||||||
|
|
||||||
|
It is possible that a malicious proposer may include a transaction in a block
|
||||||
|
that fails the AnteHandler. In this case, all state transitions for the
|
||||||
|
offending transaction are discarded.
|
||||||
|
|
||||||
|
|
||||||
|
## Other ABCI Messages
|
||||||
|
|
||||||
|
Besides `CheckTx` and `DeliverTx`, BaseApp handles the following ABCI messages.
|
||||||
|
|
||||||
|
### Info
|
||||||
|
TODO complete description
|
||||||
|
|
||||||
|
### SetOption
|
||||||
|
TODO complete description
|
||||||
|
|
||||||
|
### Query
|
||||||
|
TODO complete description
|
||||||
|
|
||||||
|
### InitChain
|
||||||
|
TODO complete description
|
||||||
|
|
||||||
|
During chain initialization InitChain runs the initialization logic directly on
|
||||||
|
the CommitMultiStore. The deliver and check states are initialized with the
|
||||||
|
ChainID.
|
||||||
|
|
||||||
|
Note that we do not commit after InitChain, so BeginBlock for block 1 starts
|
||||||
|
from the deliver state as initialized by InitChain.
|
||||||
|
|
||||||
|
### BeginBlock
|
||||||
|
TODO complete description
|
||||||
|
|
||||||
|
### EndBlock
|
||||||
|
TODO complete description
|
||||||
|
|
||||||
|
### Commit
|
||||||
|
TODO complete description
|
||||||
|
|
||||||
|
|
||||||
|
## Gas Management
|
||||||
|
|
||||||
|
### Gas: InitChain
|
||||||
|
|
||||||
|
During InitChain, the block gas meter is initialized with an infinite amount of
|
||||||
|
gas to run any genesis transactions.
|
||||||
|
|
||||||
|
Additionally, the InitChain request message includes ConsensusParams as
|
||||||
|
declared in the genesis.json file.
|
||||||
|
|
||||||
|
### Gas: BeginBlock
|
||||||
|
|
||||||
|
The block gas meter is reset during BeginBlock for the deliver state. If no
|
||||||
|
maximum block gas is set within baseapp then an infinite gas meter is set,
|
||||||
|
otherwise a gas meter with `ConsensusParam.BlockSize.MaxGas` is initialized.
|
||||||
|
|
||||||
|
### Gas: DeliverTx
|
||||||
|
|
||||||
|
Before the transaction logic is run, the `BlockGasMeter` is first checked to
|
||||||
|
see if any gas remains. If no gas remains, then `DeliverTx` immediately returns
|
||||||
|
an error.
|
||||||
|
|
||||||
|
After the transaction has been processed, the used gas (up to the transaction
|
||||||
|
gas limit) is deducted from the BlockGasMeter. If the remaining gas exceeds the
|
||||||
|
meter's limits, then DeliverTx returns an error and the transaction is not
|
||||||
|
committed.
|
||||||
|
|
|
@ -42,7 +42,7 @@ If proposal's deposit does not reach `MinDeposit` before `MaxDepositPeriod`, pro
|
||||||
There is one instance where Atom holders that deposits can be refunded:
|
There is one instance where Atom holders that deposits can be refunded:
|
||||||
* If the proposal is accepted.
|
* If the proposal is accepted.
|
||||||
|
|
||||||
Then, deposits will automatically be refunded to their respective depositer.
|
Then, deposits will automatically be refunded to their respective depositor.
|
||||||
|
|
||||||
### Proposal types
|
### Proposal types
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,8 @@ const (
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Deposit struct {
|
type Deposit struct {
|
||||||
Amount sdk.Coins // Amount of coins deposited by depositer
|
Amount sdk.Coins // Amount of coins deposited by depositor
|
||||||
Depositer crypto.address // Address of depositer
|
Depositor crypto.address // Address of depositor
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -185,8 +185,8 @@ And the pseudocode for the `ProposalProcessingQueue`:
|
||||||
// proposal was accepted at the end of the voting period
|
// proposal was accepted at the end of the voting period
|
||||||
// refund deposits (non-voters already punished)
|
// refund deposits (non-voters already punished)
|
||||||
proposal.CurrentStatus = ProposalStatusAccepted
|
proposal.CurrentStatus = ProposalStatusAccepted
|
||||||
for each (amount, depositer) in proposal.Deposits
|
for each (amount, depositor) in proposal.Deposits
|
||||||
depositer.AtomBalance += amount
|
depositor.AtomBalance += amount
|
||||||
|
|
||||||
else
|
else
|
||||||
// proposal was rejected
|
// proposal was rejected
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
# Begin-Block
|
# Begin-Block
|
||||||
|
|
||||||
## Inflation
|
Inflation occurs at the beginning of each block, however minting parameters
|
||||||
|
are only calculated once per hour.
|
||||||
|
|
||||||
Inflation occurs at the beginning of each block.
|
## NextInflationRate
|
||||||
|
|
||||||
### NextInflation
|
The target annual inflation rate is recalculated at the first block of each new
|
||||||
|
hour. The inflation is also subject to a rate change (positive or negative)
|
||||||
|
depending on the distance from the desired ratio (67%). The maximum rate change
|
||||||
|
possible is defined to be 13% per year, however the annual inflation is capped
|
||||||
|
as between 7% and 20%.
|
||||||
|
|
||||||
The target annual inflation rate is recalculated for each provisions cycle. The
|
```
|
||||||
inflation is also subject to a rate change (positive or negative) depending on
|
NextInflationRate(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
||||||
the distance from the desired ratio (67%). The maximum rate change possible is
|
|
||||||
defined to be 13% per year, however the annual inflation is capped as between
|
|
||||||
7% and 20%.
|
|
||||||
|
|
||||||
NextInflation(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
|
||||||
inflationRateChangePerYear = (1 - bondedRatio/params.GoalBonded) * params.InflationRateChange
|
inflationRateChangePerYear = (1 - bondedRatio/params.GoalBonded) * params.InflationRateChange
|
||||||
inflationRateChange = inflationRateChangePerYear/hrsPerYr
|
inflationRateChange = inflationRateChangePerYear/hrsPerYr
|
||||||
|
|
||||||
|
@ -26,3 +26,25 @@ NextInflation(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return inflation
|
return inflation
|
||||||
|
```
|
||||||
|
|
||||||
|
## NextAnnualProvisions
|
||||||
|
|
||||||
|
Calculate the annual provisions based on current total supply and inflation
|
||||||
|
rate. This parameter is calculated once per block.
|
||||||
|
|
||||||
|
```
|
||||||
|
NextAnnualProvisions(params Params, totalSupply sdk.Dec) (provisions sdk.Dec) {
|
||||||
|
return Inflation * totalSupply
|
||||||
|
```
|
||||||
|
|
||||||
|
## BlockProvision
|
||||||
|
|
||||||
|
Calculate the provisions generated for each block based on current
|
||||||
|
annual provisions
|
||||||
|
|
||||||
|
```
|
||||||
|
BlockProvision(params Params) sdk.Coin {
|
||||||
|
provisionAmt = AnnualProvisions/ params.BlocksPerYear
|
||||||
|
return sdk.NewCoin(params.MintDenom, provisionAmt.Truncate())
|
||||||
|
```
|
||||||
|
|
|
@ -8,8 +8,9 @@ The minter is a space for holding current inflation information.
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type Minter struct {
|
type Minter struct {
|
||||||
InflationLastTime time.Time // block time which the last inflation was processed
|
LastUpdate time.Time // time which the last update was made to the minter
|
||||||
Inflation sdk.Dec // current annual inflation rate
|
Inflation sdk.Dec // current annual inflation rate
|
||||||
|
AnnualProvisions sdk.Dec // current annual exptected provisions
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ type Params struct {
|
||||||
InflationMax sdk.Dec // maximum inflation rate
|
InflationMax sdk.Dec // maximum inflation rate
|
||||||
InflationMin sdk.Dec // minimum inflation rate
|
InflationMin sdk.Dec // minimum inflation rate
|
||||||
GoalBonded sdk.Dec // goal of percent bonded atoms
|
GoalBonded sdk.Dec // goal of percent bonded atoms
|
||||||
|
BlocksPerYear uint64 // expected blocks per year
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
Here contains the files required for automated deployment of either local or remote testnets.
|
Here contains the files required for automated deployment of either local or remote testnets.
|
||||||
|
|
||||||
Doing so is best accomplished using the `make` targets. For more information, see the
|
Doing so is best accomplished using the `make` targets. For more information, see the
|
||||||
[networks documentation](/docs/getting-started/networks.md)
|
[networks documentation](/docs/gaia/networks.md)
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
seeds=(1 2 4 7 9 20 32 123 124 582 1893 2989 3012 4728 37827 981928 87821 891823782 989182 89182391 \
|
||||||
|
11 22 44 77 99 2020 3232 123123 124124 582582 18931893 29892989 30123012 47284728 37827)
|
||||||
|
blocks=$1
|
||||||
|
|
||||||
|
echo "Running multi-seed import-export simulation with seeds ${seeds[@]}"
|
||||||
|
echo "Running $blocks blocks per seed"
|
||||||
|
echo "Edit scripts/simulation-after-import.sh to add new seeds. Keeping parameters in the file makes failures easy to reproduce."
|
||||||
|
echo "This script will kill all sub-simulations on SIGINT/SIGTERM (i.e. Ctrl-C)."
|
||||||
|
|
||||||
|
trap 'kill $(jobs -pr)' SIGINT SIGTERM
|
||||||
|
|
||||||
|
tmpdir=$(mktemp -d)
|
||||||
|
echo "Using temporary log directory: $tmpdir"
|
||||||
|
|
||||||
|
sim() {
|
||||||
|
seed=$1
|
||||||
|
echo "Running simulation after import with seed $seed. This may take awhile!"
|
||||||
|
file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -Iseconds -u).stdout"
|
||||||
|
echo "Writing stdout to $file..."
|
||||||
|
go test ./cmd/gaia/app -run TestGaiaSimulationAfterImport -SimulationEnabled=true -SimulationNumBlocks=$blocks \
|
||||||
|
-SimulationBlockSize=200 -SimulationCommit=true -SimulationSeed=$seed -v -timeout 24h > $file
|
||||||
|
}
|
||||||
|
|
||||||
|
i=0
|
||||||
|
pids=()
|
||||||
|
for seed in ${seeds[@]}; do
|
||||||
|
sim $seed &
|
||||||
|
pids[${i}]=$!
|
||||||
|
i=$(($i+1))
|
||||||
|
sleep 10 # start in order, nicer logs
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Simulation processes spawned, waiting for completion..."
|
||||||
|
|
||||||
|
code=0
|
||||||
|
|
||||||
|
i=0
|
||||||
|
for pid in ${pids[*]}; do
|
||||||
|
wait $pid
|
||||||
|
last=$?
|
||||||
|
seed=${seeds[${i}]}
|
||||||
|
if [ $last -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "Import/export simulation with seed $seed failed!"
|
||||||
|
code=1
|
||||||
|
else
|
||||||
|
echo "Import/export simulation with seed $seed OK"
|
||||||
|
fi
|
||||||
|
i=$(($i+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
exit $code
|
|
@ -19,7 +19,7 @@ type (
|
||||||
|
|
||||||
// AppExporter is a function that dumps all app state to
|
// AppExporter is a function that dumps all app state to
|
||||||
// JSON-serializable structure and returns the current validator set.
|
// JSON-serializable structure and returns the current validator set.
|
||||||
AppExporter func(log.Logger, dbm.DB, io.Writer, int64) (json.RawMessage, []tmtypes.GenesisValidator, error)
|
AppExporter func(log.Logger, dbm.DB, io.Writer, int64, bool) (json.RawMessage, []tmtypes.GenesisValidator, error)
|
||||||
)
|
)
|
||||||
|
|
||||||
func openDB(rootDir string) (dbm.DB, error) {
|
func openDB(rootDir string) (dbm.DB, error) {
|
||||||
|
|
|
@ -14,7 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
flagHeight = "height"
|
flagHeight = "height"
|
||||||
|
flagForZeroHeight = "for-zero-height"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExportCmd dumps app state to JSON.
|
// ExportCmd dumps app state to JSON.
|
||||||
|
@ -50,7 +51,8 @@ func ExportCmd(ctx *Context, cdc *codec.Codec, appExporter AppExporter) *cobra.C
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
height := viper.GetInt64(flagHeight)
|
height := viper.GetInt64(flagHeight)
|
||||||
appState, validators, err := appExporter(ctx.Logger, db, traceWriter, height)
|
forZeroHeight := viper.GetBool(flagForZeroHeight)
|
||||||
|
appState, validators, err := appExporter(ctx.Logger, db, traceWriter, height, forZeroHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Errorf("error exporting state: %v\n", err)
|
return errors.Errorf("error exporting state: %v\n", err)
|
||||||
}
|
}
|
||||||
|
@ -73,6 +75,7 @@ func ExportCmd(ctx *Context, cdc *codec.Codec, appExporter AppExporter) *cobra.C
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().Int64(flagHeight, -1, "Export state from a particular height (-1 means latest height)")
|
cmd.Flags().Int64(flagHeight, -1, "Export state from a particular height (-1 means latest height)")
|
||||||
|
cmd.Flags().Bool(flagForZeroHeight, false, "Export state to start at height zero (perform preproccessing)")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// SimpleGenTx is a simple genesis tx
|
// SimpleGenTx is a simple genesis tx
|
||||||
type SimpleGenTx struct {
|
type SimpleGenTx struct {
|
||||||
Addr sdk.AccAddress `json:"addr"`
|
Addr sdk.AccAddress `json:"addr"`
|
||||||
|
@ -23,7 +22,6 @@ type SimpleGenTx struct {
|
||||||
|
|
||||||
//_____________________________________________________________________
|
//_____________________________________________________________________
|
||||||
|
|
||||||
|
|
||||||
// Generate a genesis transaction
|
// Generate a genesis transaction
|
||||||
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (
|
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (
|
||||||
appGenTx, cliPrint json.RawMessage, validator types.GenesisValidator, err error) {
|
appGenTx, cliPrint json.RawMessage, validator types.GenesisValidator, err error) {
|
||||||
|
|
|
@ -11,6 +11,8 @@ import (
|
||||||
|
|
||||||
// cacheMultiStore holds many cache-wrapped stores.
|
// cacheMultiStore holds many cache-wrapped stores.
|
||||||
// Implements MultiStore.
|
// Implements MultiStore.
|
||||||
|
// NOTE: a cacheMultiStore (and MultiStores in general) should never expose the
|
||||||
|
// keys for the substores.
|
||||||
type cacheMultiStore struct {
|
type cacheMultiStore struct {
|
||||||
db CacheKVStore
|
db CacheKVStore
|
||||||
stores map[StoreKey]CacheWrap
|
stores map[StoreKey]CacheWrap
|
||||||
|
|
|
@ -73,15 +73,15 @@ func testGasKVStoreWrap(t *testing.T, store KVStore) {
|
||||||
meter := sdk.NewGasMeter(10000)
|
meter := sdk.NewGasMeter(10000)
|
||||||
|
|
||||||
store = store.Gas(meter, sdk.GasConfig{HasCost: 10})
|
store = store.Gas(meter, sdk.GasConfig{HasCost: 10})
|
||||||
require.Equal(t, int64(0), meter.GasConsumed())
|
require.Equal(t, uint64(0), meter.GasConsumed())
|
||||||
|
|
||||||
store.Has([]byte("key"))
|
store.Has([]byte("key"))
|
||||||
require.Equal(t, int64(10), meter.GasConsumed())
|
require.Equal(t, uint64(10), meter.GasConsumed())
|
||||||
|
|
||||||
store = store.Gas(meter, sdk.GasConfig{HasCost: 20})
|
store = store.Gas(meter, sdk.GasConfig{HasCost: 20})
|
||||||
|
|
||||||
store.Has([]byte("key"))
|
store.Has([]byte("key"))
|
||||||
require.Equal(t, int64(40), meter.GasConsumed())
|
require.Equal(t, uint64(40), meter.GasConsumed())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGasKVStoreWrap(t *testing.T) {
|
func TestGasKVStoreWrap(t *testing.T) {
|
||||||
|
|
|
@ -230,13 +230,19 @@ func (rs *rootMultiStore) CacheMultiStore() CacheMultiStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements MultiStore.
|
// Implements MultiStore.
|
||||||
|
// If the store does not exist, panics.
|
||||||
func (rs *rootMultiStore) GetStore(key StoreKey) Store {
|
func (rs *rootMultiStore) GetStore(key StoreKey) Store {
|
||||||
return rs.stores[key]
|
store := rs.stores[key]
|
||||||
|
if store == nil {
|
||||||
|
panic("Could not load store " + key.String())
|
||||||
|
}
|
||||||
|
return store
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKVStore implements the MultiStore interface. If tracing is enabled on the
|
// GetKVStore implements the MultiStore interface. If tracing is enabled on the
|
||||||
// rootMultiStore, a wrapped TraceKVStore will be returned with the given
|
// rootMultiStore, a wrapped TraceKVStore will be returned with the given
|
||||||
// tracer, otherwise, the original KVStore will be returned.
|
// tracer, otherwise, the original KVStore will be returned.
|
||||||
|
// If the store does not exist, panics.
|
||||||
func (rs *rootMultiStore) GetKVStore(key StoreKey) KVStore {
|
func (rs *rootMultiStore) GetKVStore(key StoreKey) KVStore {
|
||||||
store := rs.stores[key].(KVStore)
|
store := rs.stores[key].(KVStore)
|
||||||
|
|
||||||
|
|
|
@ -156,34 +156,37 @@ func TestMultiStoreQuery(t *testing.T) {
|
||||||
// Test bad path.
|
// Test bad path.
|
||||||
query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
|
query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
|
||||||
qres := multi.Query(query)
|
qres := multi.Query(query)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code))
|
require.EqualValues(t, sdk.CodeUnknownRequest, qres.Code)
|
||||||
|
require.EqualValues(t, sdk.CodespaceRoot, qres.Codespace)
|
||||||
|
|
||||||
query.Path = "h897fy32890rf63296r92"
|
query.Path = "h897fy32890rf63296r92"
|
||||||
qres = multi.Query(query)
|
qres = multi.Query(query)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code))
|
require.EqualValues(t, sdk.CodeUnknownRequest, qres.Code)
|
||||||
|
require.EqualValues(t, sdk.CodespaceRoot, qres.Codespace)
|
||||||
|
|
||||||
// Test invalid store name.
|
// Test invalid store name.
|
||||||
query.Path = "/garbage/key"
|
query.Path = "/garbage/key"
|
||||||
qres = multi.Query(query)
|
qres = multi.Query(query)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code))
|
require.EqualValues(t, sdk.CodeUnknownRequest, qres.Code)
|
||||||
|
require.EqualValues(t, sdk.CodespaceRoot, qres.Codespace)
|
||||||
|
|
||||||
// Test valid query with data.
|
// Test valid query with data.
|
||||||
query.Path = "/store1/key"
|
query.Path = "/store1/key"
|
||||||
qres = multi.Query(query)
|
qres = multi.Query(query)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code))
|
require.EqualValues(t, sdk.CodeOK, qres.Code)
|
||||||
require.Equal(t, v, qres.Value)
|
require.Equal(t, v, qres.Value)
|
||||||
|
|
||||||
// Test valid but empty query.
|
// Test valid but empty query.
|
||||||
query.Path = "/store2/key"
|
query.Path = "/store2/key"
|
||||||
query.Prove = true
|
query.Prove = true
|
||||||
qres = multi.Query(query)
|
qres = multi.Query(query)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code))
|
require.EqualValues(t, sdk.CodeOK, qres.Code)
|
||||||
require.Nil(t, qres.Value)
|
require.Nil(t, qres.Value)
|
||||||
|
|
||||||
// Test store2 data.
|
// Test store2 data.
|
||||||
query.Data = k2
|
query.Data = k2
|
||||||
qres = multi.Query(query)
|
qres = multi.Query(query)
|
||||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code))
|
require.EqualValues(t, sdk.CodeOK, qres.Code)
|
||||||
require.Equal(t, v2, qres.Value)
|
require.Equal(t, v2, qres.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
// Codespacer is a simple struct to track reserved codespaces
|
|
||||||
type Codespacer struct {
|
|
||||||
reserved map[CodespaceType]bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCodespacer generates a new Codespacer with the starting codespace
|
|
||||||
func NewCodespacer() *Codespacer {
|
|
||||||
return &Codespacer{
|
|
||||||
reserved: make(map[CodespaceType]bool),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterNext reserves and returns the next available codespace, starting from a default, and panics if the maximum codespace is reached
|
|
||||||
func (c *Codespacer) RegisterNext(codespace CodespaceType) CodespaceType {
|
|
||||||
for {
|
|
||||||
if !c.reserved[codespace] {
|
|
||||||
c.reserved[codespace] = true
|
|
||||||
return codespace
|
|
||||||
}
|
|
||||||
codespace++
|
|
||||||
if codespace == MaximumCodespace {
|
|
||||||
panic("Maximum codespace reached!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterOrPanic reserved a codespace or panics if it is unavailable
|
|
||||||
func (c *Codespacer) RegisterOrPanic(codespace CodespaceType) {
|
|
||||||
if c.reserved[codespace] {
|
|
||||||
panic("Cannot register codespace, already reserved")
|
|
||||||
}
|
|
||||||
c.reserved[codespace] = true
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRegisterNext(t *testing.T) {
|
|
||||||
codespacer := NewCodespacer()
|
|
||||||
// unregistered, allow
|
|
||||||
code1 := codespacer.RegisterNext(CodespaceType(2))
|
|
||||||
require.Equal(t, code1, CodespaceType(2))
|
|
||||||
// registered, pick next
|
|
||||||
code2 := codespacer.RegisterNext(CodespaceType(2))
|
|
||||||
require.Equal(t, code2, CodespaceType(3))
|
|
||||||
// pick next
|
|
||||||
code3 := codespacer.RegisterNext(CodespaceType(2))
|
|
||||||
require.Equal(t, code3, CodespaceType(4))
|
|
||||||
// skip 1
|
|
||||||
code4 := codespacer.RegisterNext(CodespaceType(6))
|
|
||||||
require.Equal(t, code4, CodespaceType(6))
|
|
||||||
code5 := codespacer.RegisterNext(CodespaceType(2))
|
|
||||||
require.Equal(t, code5, CodespaceType(5))
|
|
||||||
code6 := codespacer.RegisterNext(CodespaceType(2))
|
|
||||||
require.Equal(t, code6, CodespaceType(7))
|
|
||||||
// panic on maximum
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
require.NotNil(t, r, "Did not panic on maximum codespace")
|
|
||||||
}()
|
|
||||||
codespacer.RegisterNext(MaximumCodespace - 1)
|
|
||||||
codespacer.RegisterNext(MaximumCodespace - 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegisterOrPanic(t *testing.T) {
|
|
||||||
codespacer := NewCodespacer()
|
|
||||||
// unregistered, allow
|
|
||||||
code1 := codespacer.RegisterNext(CodespaceType(2))
|
|
||||||
require.Equal(t, code1, CodespaceType(2))
|
|
||||||
// panic on duplicate
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
require.NotNil(t, r, "Did not panic on duplicate codespace")
|
|
||||||
}()
|
|
||||||
codespacer.RegisterOrPanic(CodespaceType(2))
|
|
||||||
}
|
|
328
types/coin.go
328
types/coin.go
|
@ -4,23 +4,41 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Coin hold some amount of one currency
|
//-----------------------------------------------------------------------------
|
||||||
|
// Coin
|
||||||
|
|
||||||
|
// Coin hold some amount of one currency.
|
||||||
|
//
|
||||||
|
// CONTRACT: A coin will never hold a negative amount of any denomination.
|
||||||
|
//
|
||||||
|
// TODO: Make field members private for further safety.
|
||||||
type Coin struct {
|
type Coin struct {
|
||||||
Denom string `json:"denom"`
|
Denom string `json:"denom"`
|
||||||
Amount Int `json:"amount"`
|
|
||||||
|
// To allow the use of unsigned integers (see: #1273) a larger refactor will
|
||||||
|
// need to be made. So we use signed integers for now with safety measures in
|
||||||
|
// place preventing negative values being used.
|
||||||
|
Amount Int `json:"amount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCoin returns a new coin with a denomination and amount. It will panic if
|
||||||
|
// the amount is negative.
|
||||||
func NewCoin(denom string, amount Int) Coin {
|
func NewCoin(denom string, amount Int) Coin {
|
||||||
|
if amount.LT(ZeroInt()) {
|
||||||
|
panic(fmt.Sprintf("negative coin amount: %v\n", amount))
|
||||||
|
}
|
||||||
|
|
||||||
return Coin{
|
return Coin{
|
||||||
Denom: denom,
|
Denom: denom,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewInt64Coin returns a new coin with a denomination and amount. It will panic
|
||||||
|
// if the amount is negative.
|
||||||
func NewInt64Coin(denom string, amount int64) Coin {
|
func NewInt64Coin(denom string, amount int64) Coin {
|
||||||
return NewCoin(denom, NewInt(amount))
|
return NewCoin(denom, NewInt(amount))
|
||||||
}
|
}
|
||||||
|
@ -57,33 +75,46 @@ func (coin Coin) IsEqual(other Coin) bool {
|
||||||
return coin.SameDenomAs(other) && (coin.Amount.Equal(other.Amount))
|
return coin.SameDenomAs(other) && (coin.Amount.Equal(other.Amount))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPositive returns true if coin amount is positive
|
// Adds amounts of two coins with same denom. If the coins differ in denom then
|
||||||
|
// it panics.
|
||||||
|
func (coin Coin) Plus(coinB Coin) Coin {
|
||||||
|
if !coin.SameDenomAs(coinB) {
|
||||||
|
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, coinB.Denom))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Coin{coin.Denom, coin.Amount.Add(coinB.Amount)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtracts amounts of two coins with same denom. If the coins differ in denom
|
||||||
|
// then it panics.
|
||||||
|
func (coin Coin) Minus(coinB Coin) Coin {
|
||||||
|
if !coin.SameDenomAs(coinB) {
|
||||||
|
panic(fmt.Sprintf("invalid coin denominations; %s, %s", coin.Denom, coinB.Denom))
|
||||||
|
}
|
||||||
|
|
||||||
|
res := Coin{coin.Denom, coin.Amount.Sub(coinB.Amount)}
|
||||||
|
if !res.IsNotNegative() {
|
||||||
|
panic("negative count amount")
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPositive returns true if coin amount is positive.
|
||||||
|
//
|
||||||
|
// TODO: Remove once unsigned integers are used.
|
||||||
func (coin Coin) IsPositive() bool {
|
func (coin Coin) IsPositive() bool {
|
||||||
return (coin.Amount.Sign() == 1)
|
return (coin.Amount.Sign() == 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNotNegative returns true if coin amount is not negative
|
// IsNotNegative returns true if coin amount is not negative and false otherwise.
|
||||||
|
//
|
||||||
|
// TODO: Remove once unsigned integers are used.
|
||||||
func (coin Coin) IsNotNegative() bool {
|
func (coin Coin) IsNotNegative() bool {
|
||||||
return (coin.Amount.Sign() != -1)
|
return (coin.Amount.Sign() != -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds amounts of two coins with same denom
|
//-----------------------------------------------------------------------------
|
||||||
func (coin Coin) Plus(coinB Coin) Coin {
|
|
||||||
if !coin.SameDenomAs(coinB) {
|
|
||||||
return coin
|
|
||||||
}
|
|
||||||
return Coin{coin.Denom, coin.Amount.Add(coinB.Amount)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtracts amounts of two coins with same denom
|
|
||||||
func (coin Coin) Minus(coinB Coin) Coin {
|
|
||||||
if !coin.SameDenomAs(coinB) {
|
|
||||||
return coin
|
|
||||||
}
|
|
||||||
return Coin{coin.Denom, coin.Amount.Sub(coinB.Amount)}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
// Coins
|
// Coins
|
||||||
|
|
||||||
// Coins is a set of Coin, one per currency
|
// Coins is a set of Coin, one per currency
|
||||||
|
@ -101,127 +132,157 @@ func (coins Coins) String() string {
|
||||||
return out[:len(out)-1]
|
return out[:len(out)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValid asserts the Coins are sorted, and don't have 0 amounts
|
// IsValid asserts the Coins are sorted and have positive amounts.
|
||||||
func (coins Coins) IsValid() bool {
|
func (coins Coins) IsValid() bool {
|
||||||
switch len(coins) {
|
switch len(coins) {
|
||||||
case 0:
|
case 0:
|
||||||
return true
|
return true
|
||||||
case 1:
|
case 1:
|
||||||
return !coins[0].IsZero()
|
return coins[0].IsPositive()
|
||||||
default:
|
default:
|
||||||
lowDenom := coins[0].Denom
|
lowDenom := coins[0].Denom
|
||||||
|
|
||||||
for _, coin := range coins[1:] {
|
for _, coin := range coins[1:] {
|
||||||
if coin.Denom <= lowDenom {
|
if coin.Denom <= lowDenom {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if coin.IsZero() {
|
if !coin.IsPositive() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// we compare each coin against the last denom
|
// we compare each coin against the last denom
|
||||||
lowDenom = coin.Denom
|
lowDenom = coin.Denom
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plus combines two sets of coins
|
// Plus adds two sets of coins.
|
||||||
// CONTRACT: Plus will never return Coins where one Coin has a 0 amount.
|
//
|
||||||
|
// e.g.
|
||||||
|
// {2A} + {A, 2B} = {3A, 2B}
|
||||||
|
// {2A} + {0B} = {2A}
|
||||||
|
//
|
||||||
|
// NOTE: Plus operates under the invariant that coins are sorted by
|
||||||
|
// denominations.
|
||||||
|
//
|
||||||
|
// CONTRACT: Plus will never return Coins where one Coin has a non-positive
|
||||||
|
// amount. In otherwords, IsValid will always return true.
|
||||||
func (coins Coins) Plus(coinsB Coins) Coins {
|
func (coins Coins) Plus(coinsB Coins) Coins {
|
||||||
|
return coins.safePlus(coinsB)
|
||||||
|
}
|
||||||
|
|
||||||
|
// safePlus will perform addition of two coins sets. If both coin sets are
|
||||||
|
// empty, then an empty set is returned. If only a single set is empty, the
|
||||||
|
// other set is returned. Otherwise, the coins are compared in order of their
|
||||||
|
// denomination and addition only occurs when the denominations match, otherwise
|
||||||
|
// the coin is simply added to the sum assuming it's not zero.
|
||||||
|
func (coins Coins) safePlus(coinsB Coins) Coins {
|
||||||
sum := ([]Coin)(nil)
|
sum := ([]Coin)(nil)
|
||||||
indexA, indexB := 0, 0
|
indexA, indexB := 0, 0
|
||||||
lenA, lenB := len(coins), len(coinsB)
|
lenA, lenB := len(coins), len(coinsB)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if indexA == lenA {
|
if indexA == lenA {
|
||||||
if indexB == lenB {
|
if indexB == lenB {
|
||||||
|
// return nil coins if both sets are empty
|
||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
return append(sum, coinsB[indexB:]...)
|
|
||||||
|
// return set B (excluding zero coins) if set A is empty
|
||||||
|
return append(sum, removeZeroCoins(coinsB[indexB:])...)
|
||||||
} else if indexB == lenB {
|
} else if indexB == lenB {
|
||||||
return append(sum, coins[indexA:]...)
|
// return set A (excluding zero coins) if set B is empty
|
||||||
|
return append(sum, removeZeroCoins(coins[indexA:])...)
|
||||||
}
|
}
|
||||||
|
|
||||||
coinA, coinB := coins[indexA], coinsB[indexB]
|
coinA, coinB := coins[indexA], coinsB[indexB]
|
||||||
|
|
||||||
switch strings.Compare(coinA.Denom, coinB.Denom) {
|
switch strings.Compare(coinA.Denom, coinB.Denom) {
|
||||||
case -1:
|
case -1: // coin A denom < coin B denom
|
||||||
if coinA.IsZero() {
|
if !coinA.IsZero() {
|
||||||
// ignore 0 sum coin type
|
|
||||||
} else {
|
|
||||||
sum = append(sum, coinA)
|
sum = append(sum, coinA)
|
||||||
}
|
}
|
||||||
|
|
||||||
indexA++
|
indexA++
|
||||||
case 0:
|
|
||||||
if coinA.Amount.Add(coinB.Amount).IsZero() {
|
case 0: // coin A denom == coin B denom
|
||||||
// ignore 0 sum coin type
|
res := coinA.Plus(coinB)
|
||||||
} else {
|
if !res.IsZero() {
|
||||||
sum = append(sum, coinA.Plus(coinB))
|
sum = append(sum, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
indexA++
|
indexA++
|
||||||
indexB++
|
indexB++
|
||||||
case 1:
|
|
||||||
if coinB.IsZero() {
|
case 1: // coin A denom > coin B denom
|
||||||
// ignore 0 sum coin type
|
if !coinB.IsZero() {
|
||||||
} else {
|
|
||||||
sum = append(sum, coinB)
|
sum = append(sum, coinB)
|
||||||
}
|
}
|
||||||
|
|
||||||
indexB++
|
indexB++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Negative returns a set of coins with all amount negative
|
// Minus subtracts a set of coins from another.
|
||||||
func (coins Coins) Negative() Coins {
|
//
|
||||||
res := make([]Coin, 0, len(coins))
|
// e.g.
|
||||||
for _, coin := range coins {
|
// {2A, 3B} - {A} = {A, 3B}
|
||||||
res = append(res, Coin{
|
// {2A} - {0B} = {2A}
|
||||||
Denom: coin.Denom,
|
// {A, B} - {A} = {B}
|
||||||
Amount: coin.Amount.Neg(),
|
//
|
||||||
})
|
// CONTRACT: Minus will never return Coins where one Coin has a non-positive
|
||||||
}
|
// amount. In otherwords, IsValid will always return true.
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Minus subtracts a set of coins from another (adds the inverse)
|
|
||||||
func (coins Coins) Minus(coinsB Coins) Coins {
|
func (coins Coins) Minus(coinsB Coins) Coins {
|
||||||
return coins.Plus(coinsB.Negative())
|
diff, hasNeg := coins.SafeMinus(coinsB)
|
||||||
|
if hasNeg {
|
||||||
|
panic("negative coin amount")
|
||||||
|
}
|
||||||
|
|
||||||
|
return diff
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAllGT returns True iff for every denom in coins, the denom is present at a
|
// SafeMinus performs the same arithmetic as Minus but returns a boolean if any
|
||||||
|
// negative coin amount was returned.
|
||||||
|
func (coins Coins) SafeMinus(coinsB Coins) (Coins, bool) {
|
||||||
|
diff := coins.safePlus(coinsB.negative())
|
||||||
|
return diff, !diff.IsNotNegative()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAllGT returns true iff for every denom in coins, the denom is present at a
|
||||||
// greater amount in coinsB.
|
// greater amount in coinsB.
|
||||||
func (coins Coins) IsAllGT(coinsB Coins) bool {
|
func (coins Coins) IsAllGT(coinsB Coins) bool {
|
||||||
diff := coins.Minus(coinsB)
|
diff, _ := coins.SafeMinus(coinsB)
|
||||||
if len(diff) == 0 {
|
if len(diff) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff.IsPositive()
|
return diff.IsPositive()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAllGTE returns True iff for every denom in coins, the denom is present at an
|
// IsAllGTE returns true iff for every denom in coins, the denom is present at
|
||||||
// equal or greater amount in coinsB.
|
// an equal or greater amount in coinsB.
|
||||||
func (coins Coins) IsAllGTE(coinsB Coins) bool {
|
func (coins Coins) IsAllGTE(coinsB Coins) bool {
|
||||||
diff := coins.Minus(coinsB)
|
diff, _ := coins.SafeMinus(coinsB)
|
||||||
if len(diff) == 0 {
|
if len(diff) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff.IsNotNegative()
|
return diff.IsNotNegative()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAllLT returns True iff for every denom in coins, the denom is present at
|
// IsAllLT returns True iff for every denom in coins, the denom is present at
|
||||||
// a smaller amount in coinsB.
|
// a smaller amount in coinsB.
|
||||||
func (coins Coins) IsAllLT(coinsB Coins) bool {
|
func (coins Coins) IsAllLT(coinsB Coins) bool {
|
||||||
diff := coinsB.Minus(coins)
|
return coinsB.IsAllGT(coins)
|
||||||
if len(diff) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return diff.IsPositive()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAllLTE returns True iff for every denom in coins, the denom is present at
|
// IsAllLTE returns true iff for every denom in coins, the denom is present at
|
||||||
// a smaller or equal amount in coinsB.
|
// a smaller or equal amount in coinsB.
|
||||||
func (coins Coins) IsAllLTE(coinsB Coins) bool {
|
func (coins Coins) IsAllLTE(coinsB Coins) bool {
|
||||||
diff := coinsB.Minus(coins)
|
return coinsB.IsAllGTE(coins)
|
||||||
if len(diff) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return diff.IsNotNegative()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsZero returns true if there are no coins or all coins are zero.
|
// IsZero returns true if there are no coins or all coins are zero.
|
||||||
|
@ -239,40 +300,22 @@ func (coins Coins) IsEqual(coinsB Coins) bool {
|
||||||
if len(coins) != len(coinsB) {
|
if len(coins) != len(coinsB) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coins = coins.Sort()
|
||||||
|
coinsB = coinsB.Sort()
|
||||||
|
|
||||||
for i := 0; i < len(coins); i++ {
|
for i := 0; i < len(coins); i++ {
|
||||||
if coins[i].Denom != coinsB[i].Denom || !coins[i].Amount.Equal(coinsB[i].Amount) {
|
if coins[i].Denom != coinsB[i].Denom || !coins[i].Amount.Equal(coinsB[i].Amount) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPositive returns true if there is at least one coin, and all
|
// Empty returns true if there are no coins and false otherwise.
|
||||||
// currencies have a positive value
|
func (coins Coins) Empty() bool {
|
||||||
func (coins Coins) IsPositive() bool {
|
return len(coins) == 0
|
||||||
if len(coins) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, coin := range coins {
|
|
||||||
if !coin.IsPositive() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNotNegative returns true if there is no currency with a negative value
|
|
||||||
// (even no coins is true here)
|
|
||||||
func (coins Coins) IsNotNegative() bool {
|
|
||||||
if len(coins) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, coin := range coins {
|
|
||||||
if !coin.IsNotNegative() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the amount of a denom from coins
|
// Returns the amount of a denom from coins
|
||||||
|
@ -280,15 +323,18 @@ func (coins Coins) AmountOf(denom string) Int {
|
||||||
switch len(coins) {
|
switch len(coins) {
|
||||||
case 0:
|
case 0:
|
||||||
return ZeroInt()
|
return ZeroInt()
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
coin := coins[0]
|
coin := coins[0]
|
||||||
if coin.Denom == denom {
|
if coin.Denom == denom {
|
||||||
return coin.Amount
|
return coin.Amount
|
||||||
}
|
}
|
||||||
return ZeroInt()
|
return ZeroInt()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
midIdx := len(coins) / 2 // 2:1, 3:1, 4:2
|
midIdx := len(coins) / 2 // 2:1, 3:1, 4:2
|
||||||
coin := coins[midIdx]
|
coin := coins[midIdx]
|
||||||
|
|
||||||
if denom < coin.Denom {
|
if denom < coin.Denom {
|
||||||
return coins[:midIdx].AmountOf(denom)
|
return coins[:midIdx].AmountOf(denom)
|
||||||
} else if denom == coin.Denom {
|
} else if denom == coin.Denom {
|
||||||
|
@ -299,7 +345,75 @@ func (coins Coins) AmountOf(denom string) Int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
// IsPositive returns true if there is at least one coin and all currencies
|
||||||
|
// have a positive value.
|
||||||
|
//
|
||||||
|
// TODO: Remove once unsigned integers are used.
|
||||||
|
func (coins Coins) IsPositive() bool {
|
||||||
|
if len(coins) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, coin := range coins {
|
||||||
|
if !coin.IsPositive() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotNegative returns true if there is no coin amount with a negative value
|
||||||
|
// (even no coins is true here).
|
||||||
|
//
|
||||||
|
// TODO: Remove once unsigned integers are used.
|
||||||
|
func (coins Coins) IsNotNegative() bool {
|
||||||
|
if len(coins) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, coin := range coins {
|
||||||
|
if !coin.IsNotNegative() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// negative returns a set of coins with all amount negative.
|
||||||
|
//
|
||||||
|
// TODO: Remove once unsigned integers are used.
|
||||||
|
func (coins Coins) negative() Coins {
|
||||||
|
res := make([]Coin, 0, len(coins))
|
||||||
|
|
||||||
|
for _, coin := range coins {
|
||||||
|
res = append(res, Coin{
|
||||||
|
Denom: coin.Denom,
|
||||||
|
Amount: coin.Amount.Neg(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeZeroCoins removes all zero coins from the given coin set in-place.
|
||||||
|
func removeZeroCoins(coins Coins) Coins {
|
||||||
|
i, l := 0, len(coins)
|
||||||
|
for i < l {
|
||||||
|
if coins[i].IsZero() {
|
||||||
|
// remove coin
|
||||||
|
coins = append(coins[:i], coins[i+1:]...)
|
||||||
|
l--
|
||||||
|
} else {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return coins[:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
// Sort interface
|
// Sort interface
|
||||||
|
|
||||||
//nolint
|
//nolint
|
||||||
|
@ -315,7 +429,7 @@ func (coins Coins) Sort() Coins {
|
||||||
return coins
|
return coins
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Parsing
|
// Parsing
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -333,17 +447,17 @@ func ParseCoin(coinStr string) (coin Coin, err error) {
|
||||||
|
|
||||||
matches := reCoin.FindStringSubmatch(coinStr)
|
matches := reCoin.FindStringSubmatch(coinStr)
|
||||||
if matches == nil {
|
if matches == nil {
|
||||||
err = fmt.Errorf("invalid coin expression: %s", coinStr)
|
return Coin{}, fmt.Errorf("invalid coin expression: %s", coinStr)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
denomStr, amountStr := matches[2], matches[1]
|
denomStr, amountStr := matches[2], matches[1]
|
||||||
|
|
||||||
amount, err := strconv.Atoi(amountStr)
|
amount, ok := NewIntFromString(amountStr)
|
||||||
if err != nil {
|
if !ok {
|
||||||
return
|
return Coin{}, fmt.Errorf("failed to parse coin amount: %s", amountStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Coin{denomStr, NewInt(int64(amount))}, nil
|
return Coin{denomStr, amount}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseCoins will parse out a list of coins separated by commas.
|
// ParseCoins will parse out a list of coins separated by commas.
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkCoinsAdditionIntersect(b *testing.B) {
|
||||||
|
benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) {
|
||||||
|
return func(b *testing.B) {
|
||||||
|
coinsA := Coins(make([]Coin, numCoinsA))
|
||||||
|
coinsB := Coins(make([]Coin, numCoinsB))
|
||||||
|
|
||||||
|
for i := 0; i < numCoinsA; i++ {
|
||||||
|
coinsA[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
|
||||||
|
}
|
||||||
|
for i := 0; i < numCoinsB; i++ {
|
||||||
|
coinsB[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
coinsA.Plus(coinsB)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
benchmarkSizes := [][]int{{1, 1}, {5, 5}, {5, 20}, {1, 1000}, {2, 1000}}
|
||||||
|
for i := 0; i < len(benchmarkSizes); i++ {
|
||||||
|
sizeA := benchmarkSizes[i][0]
|
||||||
|
sizeB := benchmarkSizes[i][1]
|
||||||
|
b.Run(fmt.Sprintf("sizes: A_%d, B_%d", sizeA, sizeB), benchmarkingFunc(sizeA, sizeB))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkCoinsAdditionNoIntersect(b *testing.B) {
|
||||||
|
benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) {
|
||||||
|
return func(b *testing.B) {
|
||||||
|
coinsA := Coins(make([]Coin, numCoinsA))
|
||||||
|
coinsB := Coins(make([]Coin, numCoinsB))
|
||||||
|
|
||||||
|
for i := 0; i < numCoinsA; i++ {
|
||||||
|
coinsA[i] = NewCoin("COINZ_"+string(numCoinsB+i), NewInt(int64(i)))
|
||||||
|
}
|
||||||
|
for i := 0; i < numCoinsB; i++ {
|
||||||
|
coinsB[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
coinsA.Plus(coinsB)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
benchmarkSizes := [][]int{{1, 1}, {5, 5}, {5, 20}, {1, 1000}, {2, 1000}, {1000, 2}}
|
||||||
|
for i := 0; i < len(benchmarkSizes); i++ {
|
||||||
|
sizeA := benchmarkSizes[i][0]
|
||||||
|
sizeB := benchmarkSizes[i][1]
|
||||||
|
b.Run(fmt.Sprintf("sizes: A_%d, B_%d", sizeA, sizeB), benchmarkingFunc(sizeA, sizeB))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,43 +1,20 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIsPositiveCoin(t *testing.T) {
|
// ----------------------------------------------------------------------------
|
||||||
cases := []struct {
|
// Coin tests
|
||||||
inputOne Coin
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{NewInt64Coin("A", 1), true},
|
|
||||||
{NewInt64Coin("A", 0), false},
|
|
||||||
{NewInt64Coin("a", -1), false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for tcIndex, tc := range cases {
|
func TestCoin(t *testing.T) {
|
||||||
res := tc.inputOne.IsPositive()
|
require.Panics(t, func() { NewInt64Coin("A", -1) })
|
||||||
require.Equal(t, tc.expected, res, "%s positivity is incorrect, tc #%d", tc.inputOne.String(), tcIndex)
|
require.Panics(t, func() { NewCoin("A", NewInt(-1)) })
|
||||||
}
|
require.Equal(t, NewInt(5), NewInt64Coin("A", 5).Amount)
|
||||||
}
|
require.Equal(t, NewInt(5), NewCoin("A", NewInt(5)).Amount)
|
||||||
|
|
||||||
func TestIsNotNegativeCoin(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
inputOne Coin
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{NewInt64Coin("A", 1), true},
|
|
||||||
{NewInt64Coin("A", 0), true},
|
|
||||||
{NewInt64Coin("a", -1), false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for tcIndex, tc := range cases {
|
|
||||||
res := tc.inputOne.IsNotNegative()
|
|
||||||
require.Equal(t, tc.expected, res, "%s not-negativity is incorrect, tc #%d", tc.inputOne.String(), tcIndex)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSameDenomAsCoin(t *testing.T) {
|
func TestSameDenomAsCoin(t *testing.T) {
|
||||||
|
@ -49,8 +26,7 @@ func TestSameDenomAsCoin(t *testing.T) {
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), true},
|
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), true},
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("a", 1), false},
|
{NewInt64Coin("A", 1), NewInt64Coin("a", 1), false},
|
||||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
||||||
{NewInt64Coin("stake", 1), NewInt64Coin("stake", 10), true},
|
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), true},
|
||||||
{NewInt64Coin("stake", -11), NewInt64Coin("stake", 10), true},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for tcIndex, tc := range cases {
|
for tcIndex, tc := range cases {
|
||||||
|
@ -59,6 +35,78 @@ func TestSameDenomAsCoin(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsEqualCoin(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
inputOne Coin
|
||||||
|
inputTwo Coin
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), true},
|
||||||
|
{NewInt64Coin("A", 1), NewInt64Coin("a", 1), false},
|
||||||
|
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
||||||
|
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tcIndex, tc := range cases {
|
||||||
|
res := tc.inputOne.IsEqual(tc.inputTwo)
|
||||||
|
require.Equal(t, tc.expected, res, "coin equality relation is incorrect, tc #%d", tcIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlusCoin(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
inputOne Coin
|
||||||
|
inputTwo Coin
|
||||||
|
expected Coin
|
||||||
|
shouldPanic bool
|
||||||
|
}{
|
||||||
|
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), NewInt64Coin("A", 2), false},
|
||||||
|
{NewInt64Coin("A", 1), NewInt64Coin("A", 0), NewInt64Coin("A", 1), false},
|
||||||
|
{NewInt64Coin("A", 1), NewInt64Coin("B", 1), NewInt64Coin("A", 1), true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tcIndex, tc := range cases {
|
||||||
|
if tc.shouldPanic {
|
||||||
|
require.Panics(t, func() { tc.inputOne.Plus(tc.inputTwo) })
|
||||||
|
} else {
|
||||||
|
res := tc.inputOne.Plus(tc.inputTwo)
|
||||||
|
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMinusCoin(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
inputOne Coin
|
||||||
|
inputTwo Coin
|
||||||
|
expected Coin
|
||||||
|
shouldPanic bool
|
||||||
|
}{
|
||||||
|
{NewInt64Coin("A", 1), NewInt64Coin("B", 1), NewInt64Coin("A", 1), true},
|
||||||
|
{NewInt64Coin("A", 10), NewInt64Coin("A", 1), NewInt64Coin("A", 9), false},
|
||||||
|
{NewInt64Coin("A", 5), NewInt64Coin("A", 3), NewInt64Coin("A", 2), false},
|
||||||
|
{NewInt64Coin("A", 5), NewInt64Coin("A", 0), NewInt64Coin("A", 5), false},
|
||||||
|
{NewInt64Coin("A", 1), NewInt64Coin("A", 5), Coin{}, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tcIndex, tc := range cases {
|
||||||
|
if tc.shouldPanic {
|
||||||
|
require.Panics(t, func() { tc.inputOne.Minus(tc.inputTwo) })
|
||||||
|
} else {
|
||||||
|
res := tc.inputOne.Minus(tc.inputTwo)
|
||||||
|
require.Equal(t, tc.expected, res, "difference of coins is incorrect, tc #%d", tcIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tc := struct {
|
||||||
|
inputOne Coin
|
||||||
|
inputTwo Coin
|
||||||
|
expected int64
|
||||||
|
}{NewInt64Coin("A", 1), NewInt64Coin("A", 1), 0}
|
||||||
|
res := tc.inputOne.Minus(tc.inputTwo)
|
||||||
|
require.Equal(t, tc.expected, res.Amount.Int64())
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsGTECoin(t *testing.T) {
|
func TestIsGTECoin(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
inputOne Coin
|
inputOne Coin
|
||||||
|
@ -67,8 +115,7 @@ func TestIsGTECoin(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), true},
|
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), true},
|
||||||
{NewInt64Coin("A", 2), NewInt64Coin("A", 1), true},
|
{NewInt64Coin("A", 2), NewInt64Coin("A", 1), true},
|
||||||
{NewInt64Coin("A", -1), NewInt64Coin("A", 5), false},
|
{NewInt64Coin("A", 1), NewInt64Coin("B", 1), false},
|
||||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for tcIndex, tc := range cases {
|
for tcIndex, tc := range cases {
|
||||||
|
@ -85,7 +132,6 @@ func TestIsLTCoin(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), false},
|
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), false},
|
||||||
{NewInt64Coin("A", 2), NewInt64Coin("A", 1), false},
|
{NewInt64Coin("A", 2), NewInt64Coin("A", 1), false},
|
||||||
{NewInt64Coin("A", -1), NewInt64Coin("A", 5), true},
|
|
||||||
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), false},
|
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), false},
|
||||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
||||||
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), false},
|
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), false},
|
||||||
|
@ -98,76 +144,18 @@ func TestIsLTCoin(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsEqualCoin(t *testing.T) {
|
func TestCoinIsZero(t *testing.T) {
|
||||||
cases := []struct {
|
coin := NewInt64Coin("A", 0)
|
||||||
inputOne Coin
|
res := coin.IsZero()
|
||||||
inputTwo Coin
|
require.True(t, res)
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), true},
|
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("a", 1), false},
|
|
||||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
|
||||||
{NewInt64Coin("stake", 1), NewInt64Coin("stake", 10), false},
|
|
||||||
{NewInt64Coin("stake", -11), NewInt64Coin("stake", 10), false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for tcIndex, tc := range cases {
|
coin = NewInt64Coin("A", 1)
|
||||||
res := tc.inputOne.IsEqual(tc.inputTwo)
|
res = coin.IsZero()
|
||||||
require.Equal(t, tc.expected, res, "coin equality relation is incorrect, tc #%d", tcIndex)
|
require.False(t, res)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlusCoin(t *testing.T) {
|
// ----------------------------------------------------------------------------
|
||||||
cases := []struct {
|
// Coins tests
|
||||||
inputOne Coin
|
|
||||||
inputTwo Coin
|
|
||||||
expected Coin
|
|
||||||
}{
|
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), NewInt64Coin("A", 2)},
|
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("B", 1), NewInt64Coin("A", 1)},
|
|
||||||
{NewInt64Coin("asdf", -4), NewInt64Coin("asdf", 5), NewInt64Coin("asdf", 1)},
|
|
||||||
}
|
|
||||||
|
|
||||||
for tcIndex, tc := range cases {
|
|
||||||
res := tc.inputOne.Plus(tc.inputTwo)
|
|
||||||
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
tc := struct {
|
|
||||||
inputOne Coin
|
|
||||||
inputTwo Coin
|
|
||||||
expected int64
|
|
||||||
}{NewInt64Coin("asdf", -1), NewInt64Coin("asdf", 1), 0}
|
|
||||||
res := tc.inputOne.Plus(tc.inputTwo)
|
|
||||||
require.Equal(t, tc.expected, res.Amount.Int64())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMinusCoin(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
inputOne Coin
|
|
||||||
inputTwo Coin
|
|
||||||
expected Coin
|
|
||||||
}{
|
|
||||||
|
|
||||||
{NewInt64Coin("A", 1), NewInt64Coin("B", 1), NewInt64Coin("A", 1)},
|
|
||||||
{NewInt64Coin("asdf", -4), NewInt64Coin("asdf", 5), NewInt64Coin("asdf", -9)},
|
|
||||||
{NewInt64Coin("asdf", 10), NewInt64Coin("asdf", 1), NewInt64Coin("asdf", 9)},
|
|
||||||
}
|
|
||||||
|
|
||||||
for tcIndex, tc := range cases {
|
|
||||||
res := tc.inputOne.Minus(tc.inputTwo)
|
|
||||||
require.Equal(t, tc.expected, res, "difference of coins is incorrect, tc #%d", tcIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
tc := struct {
|
|
||||||
inputOne Coin
|
|
||||||
inputTwo Coin
|
|
||||||
expected int64
|
|
||||||
}{NewInt64Coin("A", 1), NewInt64Coin("A", 1), 0}
|
|
||||||
res := tc.inputOne.Minus(tc.inputTwo)
|
|
||||||
require.Equal(t, tc.expected, res.Amount.Int64())
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsZeroCoins(t *testing.T) {
|
func TestIsZeroCoins(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
@ -199,8 +187,7 @@ func TestEqualCoins(t *testing.T) {
|
||||||
{Coins{NewInt64Coin("A", 0)}, Coins{NewInt64Coin("B", 0)}, false},
|
{Coins{NewInt64Coin("A", 0)}, Coins{NewInt64Coin("B", 0)}, false},
|
||||||
{Coins{NewInt64Coin("A", 0)}, Coins{NewInt64Coin("A", 1)}, false},
|
{Coins{NewInt64Coin("A", 0)}, Coins{NewInt64Coin("A", 1)}, false},
|
||||||
{Coins{NewInt64Coin("A", 0)}, Coins{NewInt64Coin("A", 0), NewInt64Coin("B", 1)}, false},
|
{Coins{NewInt64Coin("A", 0)}, Coins{NewInt64Coin("A", 0), NewInt64Coin("B", 1)}, false},
|
||||||
// TODO: is it expected behaviour? shouldn't we sort the coins before comparing them?
|
{Coins{NewInt64Coin("A", 0), NewInt64Coin("B", 1)}, Coins{NewInt64Coin("B", 1), NewInt64Coin("A", 0)}, true},
|
||||||
{Coins{NewInt64Coin("A", 0), NewInt64Coin("B", 1)}, Coins{NewInt64Coin("B", 1), NewInt64Coin("A", 0)}, false},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for tcnum, tc := range cases {
|
for tcnum, tc := range cases {
|
||||||
|
@ -209,16 +196,65 @@ func TestEqualCoins(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCoins(t *testing.T) {
|
func TestPlusCoins(t *testing.T) {
|
||||||
|
zero := NewInt(0)
|
||||||
|
one := NewInt(1)
|
||||||
|
two := NewInt(2)
|
||||||
|
|
||||||
//Define the coins to be used in tests
|
cases := []struct {
|
||||||
|
inputOne Coins
|
||||||
|
inputTwo Coins
|
||||||
|
expected Coins
|
||||||
|
}{
|
||||||
|
{Coins{{"A", one}, {"B", one}}, Coins{{"A", one}, {"B", one}}, Coins{{"A", two}, {"B", two}}},
|
||||||
|
{Coins{{"A", zero}, {"B", one}}, Coins{{"A", zero}, {"B", zero}}, Coins{{"B", one}}},
|
||||||
|
{Coins{{"A", two}}, Coins{{"B", zero}}, Coins{{"A", two}}},
|
||||||
|
{Coins{{"A", one}}, Coins{{"A", one}, {"B", two}}, Coins{{"A", two}, {"B", two}}},
|
||||||
|
{Coins{{"A", zero}, {"B", zero}}, Coins{{"A", zero}, {"B", zero}}, Coins(nil)},
|
||||||
|
}
|
||||||
|
|
||||||
|
for tcIndex, tc := range cases {
|
||||||
|
res := tc.inputOne.Plus(tc.inputTwo)
|
||||||
|
assert.True(t, res.IsValid())
|
||||||
|
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMinusCoins(t *testing.T) {
|
||||||
|
zero := NewInt(0)
|
||||||
|
one := NewInt(1)
|
||||||
|
two := NewInt(2)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
inputOne Coins
|
||||||
|
inputTwo Coins
|
||||||
|
expected Coins
|
||||||
|
shouldPanic bool
|
||||||
|
}{
|
||||||
|
{Coins{{"A", two}}, Coins{{"A", one}, {"B", two}}, Coins{{"A", one}, {"B", two}}, true},
|
||||||
|
{Coins{{"A", two}}, Coins{{"B", zero}}, Coins{{"A", two}}, false},
|
||||||
|
{Coins{{"A", one}}, Coins{{"B", zero}}, Coins{{"A", one}}, false},
|
||||||
|
{Coins{{"A", one}, {"B", one}}, Coins{{"A", one}}, Coins{{"B", one}}, false},
|
||||||
|
{Coins{{"A", one}, {"B", one}}, Coins{{"A", two}}, Coins{}, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
if tc.shouldPanic {
|
||||||
|
require.Panics(t, func() { tc.inputOne.Minus(tc.inputTwo) })
|
||||||
|
} else {
|
||||||
|
res := tc.inputOne.Minus(tc.inputTwo)
|
||||||
|
assert.True(t, res.IsValid())
|
||||||
|
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCoins(t *testing.T) {
|
||||||
good := Coins{
|
good := Coins{
|
||||||
{"GAS", NewInt(1)},
|
{"GAS", NewInt(1)},
|
||||||
{"MINERAL", NewInt(1)},
|
{"MINERAL", NewInt(1)},
|
||||||
{"TREE", NewInt(1)},
|
{"TREE", NewInt(1)},
|
||||||
}
|
}
|
||||||
neg := good.Negative()
|
|
||||||
sum := good.Plus(neg)
|
|
||||||
empty := Coins{
|
empty := Coins{
|
||||||
{"GOLD", NewInt(0)},
|
{"GOLD", NewInt(0)},
|
||||||
}
|
}
|
||||||
|
@ -228,6 +264,7 @@ func TestCoins(t *testing.T) {
|
||||||
{"GAS", NewInt(1)},
|
{"GAS", NewInt(1)},
|
||||||
{"MINERAL", NewInt(1)},
|
{"MINERAL", NewInt(1)},
|
||||||
}
|
}
|
||||||
|
|
||||||
// both are after the first one, but the second and third are in the wrong order
|
// both are after the first one, but the second and third are in the wrong order
|
||||||
badSort2 := Coins{
|
badSort2 := Coins{
|
||||||
{"GAS", NewInt(1)},
|
{"GAS", NewInt(1)},
|
||||||
|
@ -251,13 +288,10 @@ func TestCoins(t *testing.T) {
|
||||||
assert.True(t, good.IsAllGTE(empty), "Expected %v to be >= %v", good, empty)
|
assert.True(t, good.IsAllGTE(empty), "Expected %v to be >= %v", good, empty)
|
||||||
assert.False(t, good.IsAllLT(empty), "Expected %v to be < %v", good, empty)
|
assert.False(t, good.IsAllLT(empty), "Expected %v to be < %v", good, empty)
|
||||||
assert.True(t, empty.IsAllLT(good), "Expected %v to be < %v", empty, good)
|
assert.True(t, empty.IsAllLT(good), "Expected %v to be < %v", empty, good)
|
||||||
assert.False(t, neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
|
|
||||||
assert.Zero(t, len(sum), "Expected 0 coins")
|
|
||||||
assert.False(t, badSort1.IsValid(), "Coins are not sorted")
|
assert.False(t, badSort1.IsValid(), "Coins are not sorted")
|
||||||
assert.False(t, badSort2.IsValid(), "Coins are not sorted")
|
assert.False(t, badSort2.IsValid(), "Coins are not sorted")
|
||||||
assert.False(t, badAmt.IsValid(), "Coins cannot include 0 amounts")
|
assert.False(t, badAmt.IsValid(), "Coins cannot include 0 amounts")
|
||||||
assert.False(t, dup.IsValid(), "Duplicate coin")
|
assert.False(t, dup.IsValid(), "Duplicate coin")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCoinsGT(t *testing.T) {
|
func TestCoinsGT(t *testing.T) {
|
||||||
|
@ -314,32 +348,6 @@ func TestCoinsLTE(t *testing.T) {
|
||||||
assert.True(t, Coins{}.IsAllLTE(Coins{{"A", one}}))
|
assert.True(t, Coins{}.IsAllLTE(Coins{{"A", one}}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlusCoins(t *testing.T) {
|
|
||||||
one := NewInt(1)
|
|
||||||
zero := NewInt(0)
|
|
||||||
negone := NewInt(-1)
|
|
||||||
two := NewInt(2)
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
inputOne Coins
|
|
||||||
inputTwo Coins
|
|
||||||
expected Coins
|
|
||||||
}{
|
|
||||||
{Coins{{"A", one}, {"B", one}}, Coins{{"A", one}, {"B", one}}, Coins{{"A", two}, {"B", two}}},
|
|
||||||
{Coins{{"A", zero}, {"B", one}}, Coins{{"A", zero}, {"B", zero}}, Coins{{"B", one}}},
|
|
||||||
{Coins{{"A", zero}, {"B", zero}}, Coins{{"A", zero}, {"B", zero}}, Coins(nil)},
|
|
||||||
{Coins{{"A", one}, {"B", zero}}, Coins{{"A", negone}, {"B", zero}}, Coins(nil)},
|
|
||||||
{Coins{{"A", negone}, {"B", zero}}, Coins{{"A", zero}, {"B", zero}}, Coins{{"A", negone}}},
|
|
||||||
}
|
|
||||||
|
|
||||||
for tcIndex, tc := range cases {
|
|
||||||
res := tc.inputOne.Plus(tc.inputTwo)
|
|
||||||
assert.True(t, res.IsValid())
|
|
||||||
require.Equal(t, tc.expected, res, "sum of coins is incorrect, tc #%d", tcIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Test the parsing of Coin and Coins
|
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
one := NewInt(1)
|
one := NewInt(1)
|
||||||
|
|
||||||
|
@ -370,11 +378,9 @@ func TestParse(t *testing.T) {
|
||||||
require.Equal(t, tc.expected, res, "coin parsing was incorrect, tc #%d", tcIndex)
|
require.Equal(t, tc.expected, res, "coin parsing was incorrect, tc #%d", tcIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSortCoins(t *testing.T) {
|
func TestSortCoins(t *testing.T) {
|
||||||
|
|
||||||
good := Coins{
|
good := Coins{
|
||||||
NewInt64Coin("GAS", 1),
|
NewInt64Coin("GAS", 1),
|
||||||
NewInt64Coin("MINERAL", 1),
|
NewInt64Coin("MINERAL", 1),
|
||||||
|
@ -424,7 +430,6 @@ func TestSortCoins(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAmountOf(t *testing.T) {
|
func TestAmountOf(t *testing.T) {
|
||||||
|
|
||||||
case0 := Coins{}
|
case0 := Coins{}
|
||||||
case1 := Coins{
|
case1 := Coins{
|
||||||
NewInt64Coin("", 0),
|
NewInt64Coin("", 0),
|
||||||
|
@ -481,55 +486,3 @@ func TestAmountOf(t *testing.T) {
|
||||||
assert.Equal(t, NewInt(tc.amountOfTREE), tc.coins.AmountOf("TREE"))
|
assert.Equal(t, NewInt(tc.amountOfTREE), tc.coins.AmountOf("TREE"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCoinsAdditionIntersect(b *testing.B) {
|
|
||||||
benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) {
|
|
||||||
return func(b *testing.B) {
|
|
||||||
coinsA := Coins(make([]Coin, numCoinsA))
|
|
||||||
coinsB := Coins(make([]Coin, numCoinsB))
|
|
||||||
for i := 0; i < numCoinsA; i++ {
|
|
||||||
coinsA[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
|
|
||||||
}
|
|
||||||
for i := 0; i < numCoinsB; i++ {
|
|
||||||
coinsB[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
coinsA.Plus(coinsB)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
benchmarkSizes := [][]int{{1, 1}, {5, 5}, {5, 20}, {1, 1000}, {2, 1000}}
|
|
||||||
for i := 0; i < len(benchmarkSizes); i++ {
|
|
||||||
sizeA := benchmarkSizes[i][0]
|
|
||||||
sizeB := benchmarkSizes[i][1]
|
|
||||||
b.Run(fmt.Sprintf("sizes: A_%d, B_%d", sizeA, sizeB), benchmarkingFunc(sizeA, sizeB))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkCoinsAdditionNoIntersect(b *testing.B) {
|
|
||||||
benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) {
|
|
||||||
return func(b *testing.B) {
|
|
||||||
coinsA := Coins(make([]Coin, numCoinsA))
|
|
||||||
coinsB := Coins(make([]Coin, numCoinsB))
|
|
||||||
for i := 0; i < numCoinsA; i++ {
|
|
||||||
coinsA[i] = NewCoin("COINZ_"+string(numCoinsB+i), NewInt(int64(i)))
|
|
||||||
}
|
|
||||||
for i := 0; i < numCoinsB; i++ {
|
|
||||||
coinsB[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
coinsA.Plus(coinsB)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
benchmarkSizes := [][]int{{1, 1}, {5, 5}, {5, 20}, {1, 1000}, {2, 1000}, {1000, 2}}
|
|
||||||
for i := 0; i < len(benchmarkSizes); i++ {
|
|
||||||
sizeA := benchmarkSizes[i][0]
|
|
||||||
sizeB := benchmarkSizes[i][1]
|
|
||||||
b.Run(fmt.Sprintf("sizes: A_%d, B_%d", sizeA, sizeB), benchmarkingFunc(sizeA, sizeB))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -73,12 +73,12 @@ func (c Context) Value(key interface{}) interface{} {
|
||||||
|
|
||||||
// KVStore fetches a KVStore from the MultiStore.
|
// KVStore fetches a KVStore from the MultiStore.
|
||||||
func (c Context) KVStore(key StoreKey) KVStore {
|
func (c Context) KVStore(key StoreKey) KVStore {
|
||||||
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedKVGasConfig)
|
return c.MultiStore().GetKVStore(key).Gas(c.GasMeter(), cachedKVGasConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransientStore fetches a TransientStore from the MultiStore.
|
// TransientStore fetches a TransientStore from the MultiStore.
|
||||||
func (c Context) TransientStore(key StoreKey) KVStore {
|
func (c Context) TransientStore(key StoreKey) KVStore {
|
||||||
return c.multiStore().GetKVStore(key).Gas(c.GasMeter(), cachedTransientGasConfig)
|
return c.MultiStore().GetKVStore(key).Gas(c.GasMeter(), cachedTransientGasConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
@ -133,20 +133,17 @@ const (
|
||||||
contextKeyMultiStore contextKey = iota
|
contextKeyMultiStore contextKey = iota
|
||||||
contextKeyBlockHeader
|
contextKeyBlockHeader
|
||||||
contextKeyBlockHeight
|
contextKeyBlockHeight
|
||||||
contextKeyConsensusParams
|
|
||||||
contextKeyChainID
|
contextKeyChainID
|
||||||
contextKeyIsCheckTx
|
contextKeyIsCheckTx
|
||||||
contextKeyTxBytes
|
contextKeyTxBytes
|
||||||
contextKeyLogger
|
contextKeyLogger
|
||||||
contextKeyVoteInfos
|
contextKeyVoteInfos
|
||||||
contextKeyGasMeter
|
contextKeyGasMeter
|
||||||
|
contextKeyBlockGasMeter
|
||||||
contextKeyMinimumFees
|
contextKeyMinimumFees
|
||||||
)
|
)
|
||||||
|
|
||||||
// NOTE: Do not expose MultiStore.
|
func (c Context) MultiStore() MultiStore {
|
||||||
// MultiStore exposes all the keys.
|
|
||||||
// Instead, pass the context and the store key.
|
|
||||||
func (c Context) multiStore() MultiStore {
|
|
||||||
return c.Value(contextKeyMultiStore).(MultiStore)
|
return c.Value(contextKeyMultiStore).(MultiStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,10 +151,6 @@ func (c Context) BlockHeader() abci.Header { return c.Value(contextKeyBlockHeade
|
||||||
|
|
||||||
func (c Context) BlockHeight() int64 { return c.Value(contextKeyBlockHeight).(int64) }
|
func (c Context) BlockHeight() int64 { return c.Value(contextKeyBlockHeight).(int64) }
|
||||||
|
|
||||||
func (c Context) ConsensusParams() abci.ConsensusParams {
|
|
||||||
return c.Value(contextKeyConsensusParams).(abci.ConsensusParams)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Context) ChainID() string { return c.Value(contextKeyChainID).(string) }
|
func (c Context) ChainID() string { return c.Value(contextKeyChainID).(string) }
|
||||||
|
|
||||||
func (c Context) TxBytes() []byte { return c.Value(contextKeyTxBytes).([]byte) }
|
func (c Context) TxBytes() []byte { return c.Value(contextKeyTxBytes).([]byte) }
|
||||||
|
@ -170,11 +163,15 @@ func (c Context) VoteInfos() []abci.VoteInfo {
|
||||||
|
|
||||||
func (c Context) GasMeter() GasMeter { return c.Value(contextKeyGasMeter).(GasMeter) }
|
func (c Context) GasMeter() GasMeter { return c.Value(contextKeyGasMeter).(GasMeter) }
|
||||||
|
|
||||||
|
func (c Context) BlockGasMeter() GasMeter { return c.Value(contextKeyBlockGasMeter).(GasMeter) }
|
||||||
|
|
||||||
func (c Context) IsCheckTx() bool { return c.Value(contextKeyIsCheckTx).(bool) }
|
func (c Context) IsCheckTx() bool { return c.Value(contextKeyIsCheckTx).(bool) }
|
||||||
|
|
||||||
func (c Context) MinimumFees() Coins { return c.Value(contextKeyMinimumFees).(Coins) }
|
func (c Context) MinimumFees() Coins { return c.Value(contextKeyMinimumFees).(Coins) }
|
||||||
|
|
||||||
func (c Context) WithMultiStore(ms MultiStore) Context { return c.withValue(contextKeyMultiStore, ms) }
|
func (c Context) WithMultiStore(ms MultiStore) Context {
|
||||||
|
return c.withValue(contextKeyMultiStore, ms)
|
||||||
|
}
|
||||||
|
|
||||||
func (c Context) WithBlockHeader(header abci.Header) Context {
|
func (c Context) WithBlockHeader(header abci.Header) Context {
|
||||||
var _ proto.Message = &header // for cloning.
|
var _ proto.Message = &header // for cloning.
|
||||||
|
@ -199,14 +196,6 @@ func (c Context) WithBlockHeight(height int64) Context {
|
||||||
return c.withValue(contextKeyBlockHeight, height).withValue(contextKeyBlockHeader, newHeader)
|
return c.withValue(contextKeyBlockHeight, height).withValue(contextKeyBlockHeader, newHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {
|
|
||||||
if params == nil {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
return c.withValue(contextKeyConsensusParams, params).
|
|
||||||
WithGasMeter(NewGasMeter(params.BlockSize.MaxGas))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Context) WithChainID(chainID string) Context { return c.withValue(contextKeyChainID, chainID) }
|
func (c Context) WithChainID(chainID string) Context { return c.withValue(contextKeyChainID, chainID) }
|
||||||
|
|
||||||
func (c Context) WithTxBytes(txBytes []byte) Context { return c.withValue(contextKeyTxBytes, txBytes) }
|
func (c Context) WithTxBytes(txBytes []byte) Context { return c.withValue(contextKeyTxBytes, txBytes) }
|
||||||
|
@ -219,6 +208,10 @@ func (c Context) WithVoteInfos(VoteInfos []abci.VoteInfo) Context {
|
||||||
|
|
||||||
func (c Context) WithGasMeter(meter GasMeter) Context { return c.withValue(contextKeyGasMeter, meter) }
|
func (c Context) WithGasMeter(meter GasMeter) Context { return c.withValue(contextKeyGasMeter, meter) }
|
||||||
|
|
||||||
|
func (c Context) WithBlockGasMeter(meter GasMeter) Context {
|
||||||
|
return c.withValue(contextKeyBlockGasMeter, meter)
|
||||||
|
}
|
||||||
|
|
||||||
func (c Context) WithIsCheckTx(isCheckTx bool) Context {
|
func (c Context) WithIsCheckTx(isCheckTx bool) Context {
|
||||||
return c.withValue(contextKeyIsCheckTx, isCheckTx)
|
return c.withValue(contextKeyIsCheckTx, isCheckTx)
|
||||||
}
|
}
|
||||||
|
@ -230,7 +223,7 @@ func (c Context) WithMinimumFees(minFees Coins) Context {
|
||||||
// Cache the multistore and return a new cached context. The cached context is
|
// Cache the multistore and return a new cached context. The cached context is
|
||||||
// written to the context when writeCache is called.
|
// written to the context when writeCache is called.
|
||||||
func (c Context) CacheContext() (cc Context, writeCache func()) {
|
func (c Context) CacheContext() (cc Context, writeCache func()) {
|
||||||
cms := c.multiStore().CacheMultiStore()
|
cms := c.MultiStore().CacheMultiStore()
|
||||||
cc = c.WithMultiStore(cms)
|
cc = c.WithMultiStore(cms)
|
||||||
return cc, cms.Write
|
return cc, cms.Write
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,10 +172,21 @@ func NewDecFromStr(str string) (d Dec, err Error) {
|
||||||
return Dec{combined}, nil
|
return Dec{combined}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decimal from string, panic on error
|
||||||
|
func MustNewDecFromStr(s string) Dec {
|
||||||
|
dec, err := NewDecFromStr(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return dec
|
||||||
|
}
|
||||||
|
|
||||||
//______________________________________________________________________________________________
|
//______________________________________________________________________________________________
|
||||||
//nolint
|
//nolint
|
||||||
func (d Dec) IsNil() bool { return d.Int == nil } // is decimal nil
|
func (d Dec) IsNil() bool { return d.Int == nil } // is decimal nil
|
||||||
func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // is equal to zero
|
func (d Dec) IsZero() bool { return (d.Int).Sign() == 0 } // is equal to zero
|
||||||
|
func (d Dec) IsNegative() bool { return (d.Int).Sign() == -1 } // is negative
|
||||||
|
func (d Dec) IsPositive() bool { return (d.Int).Sign() == 1 } // is positive
|
||||||
func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } // equal decimals
|
func (d Dec) Equal(d2 Dec) bool { return (d.Int).Cmp(d2.Int) == 0 } // equal decimals
|
||||||
func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) > 0 } // greater than
|
func (d Dec) GT(d2 Dec) bool { return (d.Int).Cmp(d2.Int) > 0 } // greater than
|
||||||
func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal
|
func (d Dec) GTE(d2 Dec) bool { return (d.Int).Cmp(d2.Int) >= 0 } // greater than or equal
|
||||||
|
@ -252,6 +263,14 @@ func (d Dec) IsInteger() bool {
|
||||||
return new(big.Int).Rem(d.Int, precisionReuse).Sign() == 0
|
return new(big.Int).Rem(d.Int, precisionReuse).Sign() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// format decimal state
|
||||||
|
func (d Dec) Format(s fmt.State, verb rune) {
|
||||||
|
_, err := s.Write([]byte(d.String()))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d Dec) String() string {
|
func (d Dec) String() string {
|
||||||
bz, err := d.Int.MarshalText()
|
bz, err := d.Int.MarshalText()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,37 +10,22 @@ import (
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ABCICodeType - combined codetype / codespace
|
// CodeType - ABCI code identifier within codespace
|
||||||
type ABCICodeType uint32
|
type CodeType uint32
|
||||||
|
|
||||||
// CodeType - code identifier within codespace
|
|
||||||
type CodeType uint16
|
|
||||||
|
|
||||||
// CodespaceType - codespace identifier
|
// CodespaceType - codespace identifier
|
||||||
type CodespaceType uint16
|
type CodespaceType string
|
||||||
|
|
||||||
// IsOK - is everything okay?
|
// IsOK - is everything okay?
|
||||||
func (code ABCICodeType) IsOK() bool {
|
func (code CodeType) IsOK() bool {
|
||||||
if code == ABCICodeOK {
|
if code == CodeOK {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the abci code from the local code and codespace
|
|
||||||
func ToABCICode(space CodespaceType, code CodeType) ABCICodeType {
|
|
||||||
// TODO: Make Tendermint more aware of codespaces.
|
|
||||||
if space == CodespaceRoot && code == CodeOK {
|
|
||||||
return ABCICodeOK
|
|
||||||
}
|
|
||||||
return ABCICodeType((uint32(space) << 16) | uint32(code))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SDK error codes
|
// SDK error codes
|
||||||
const (
|
const (
|
||||||
// ABCI error codes
|
|
||||||
ABCICodeOK ABCICodeType = 0
|
|
||||||
|
|
||||||
// Base error codes
|
// Base error codes
|
||||||
CodeOK CodeType = 0
|
CodeOK CodeType = 0
|
||||||
CodeInternal CodeType = 1
|
CodeInternal CodeType = 1
|
||||||
|
@ -62,11 +47,8 @@ const (
|
||||||
// CodespaceRoot is a codespace for error codes in this file only.
|
// CodespaceRoot is a codespace for error codes in this file only.
|
||||||
// Notice that 0 is an "unset" codespace, which can be overridden with
|
// Notice that 0 is an "unset" codespace, which can be overridden with
|
||||||
// Error.WithDefaultCodespace().
|
// Error.WithDefaultCodespace().
|
||||||
CodespaceUndefined CodespaceType = 0
|
CodespaceUndefined CodespaceType = ""
|
||||||
CodespaceRoot CodespaceType = 1
|
CodespaceRoot CodespaceType = "sdk"
|
||||||
|
|
||||||
// Maximum reservable codespace (2^16 - 1)
|
|
||||||
MaximumCodespace CodespaceType = 65535
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func unknownCodeMsg(code CodeType) string {
|
func unknownCodeMsg(code CodeType) string {
|
||||||
|
@ -185,7 +167,6 @@ type Error interface {
|
||||||
Code() CodeType
|
Code() CodeType
|
||||||
Codespace() CodespaceType
|
Codespace() CodespaceType
|
||||||
ABCILog() string
|
ABCILog() string
|
||||||
ABCICode() ABCICodeType
|
|
||||||
Result() Result
|
Result() Result
|
||||||
QueryResult() abci.ResponseQuery
|
QueryResult() abci.ResponseQuery
|
||||||
}
|
}
|
||||||
|
@ -239,17 +220,12 @@ func (err *sdkError) TraceSDK(format string, args ...interface{}) Error {
|
||||||
// Implements ABCIError.
|
// Implements ABCIError.
|
||||||
func (err *sdkError) Error() string {
|
func (err *sdkError) Error() string {
|
||||||
return fmt.Sprintf(`ERROR:
|
return fmt.Sprintf(`ERROR:
|
||||||
Codespace: %d
|
Codespace: %s
|
||||||
Code: %d
|
Code: %d
|
||||||
Message: %#v
|
Message: %#v
|
||||||
`, err.codespace, err.code, err.cmnError.Error())
|
`, err.codespace, err.code, err.cmnError.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements ABCIError.
|
|
||||||
func (err *sdkError) ABCICode() ABCICodeType {
|
|
||||||
return ToABCICode(err.codespace, err.code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements Error.
|
// Implements Error.
|
||||||
func (err *sdkError) Codespace() CodespaceType {
|
func (err *sdkError) Codespace() CodespaceType {
|
||||||
return err.codespace
|
return err.codespace
|
||||||
|
@ -267,7 +243,6 @@ func (err *sdkError) ABCILog() string {
|
||||||
jsonErr := humanReadableError{
|
jsonErr := humanReadableError{
|
||||||
Codespace: err.codespace,
|
Codespace: err.codespace,
|
||||||
Code: err.code,
|
Code: err.code,
|
||||||
ABCICode: err.ABCICode(),
|
|
||||||
Message: errMsg,
|
Message: errMsg,
|
||||||
}
|
}
|
||||||
bz, er := cdc.MarshalJSON(jsonErr)
|
bz, er := cdc.MarshalJSON(jsonErr)
|
||||||
|
@ -280,16 +255,18 @@ func (err *sdkError) ABCILog() string {
|
||||||
|
|
||||||
func (err *sdkError) Result() Result {
|
func (err *sdkError) Result() Result {
|
||||||
return Result{
|
return Result{
|
||||||
Code: err.ABCICode(),
|
Code: err.Code(),
|
||||||
Log: err.ABCILog(),
|
Codespace: err.Codespace(),
|
||||||
|
Log: err.ABCILog(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryResult allows us to return sdk.Error.QueryResult() in query responses
|
// QueryResult allows us to return sdk.Error.QueryResult() in query responses
|
||||||
func (err *sdkError) QueryResult() abci.ResponseQuery {
|
func (err *sdkError) QueryResult() abci.ResponseQuery {
|
||||||
return abci.ResponseQuery{
|
return abci.ResponseQuery{
|
||||||
Code: uint32(err.ABCICode()),
|
Code: uint32(err.Code()),
|
||||||
Log: err.ABCILog(),
|
Codespace: string(err.Codespace()),
|
||||||
|
Log: err.ABCILog(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +301,5 @@ func mustGetMsgIndex(abciLog string) int {
|
||||||
type humanReadableError struct {
|
type humanReadableError struct {
|
||||||
Codespace CodespaceType `json:"codespace"`
|
Codespace CodespaceType `json:"codespace"`
|
||||||
Code CodeType `json:"code"`
|
Code CodeType `json:"code"`
|
||||||
ABCICode ABCICodeType `json:"abci_code"`
|
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ var errFns = []errFn{
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCodeType(t *testing.T) {
|
func TestCodeType(t *testing.T) {
|
||||||
require.True(t, ABCICodeOK.IsOK())
|
require.True(t, CodeOK.IsOK())
|
||||||
|
|
||||||
for tcnum, c := range codeTypes {
|
for tcnum, c := range codeTypes {
|
||||||
msg := CodeToDefaultMsg(c)
|
msg := CodeToDefaultMsg(c)
|
||||||
|
@ -59,12 +59,9 @@ func TestErrFn(t *testing.T) {
|
||||||
codeType := codeTypes[i]
|
codeType := codeTypes[i]
|
||||||
require.Equal(t, err.Code(), codeType, "Err function expected to return proper code. tc #%d", i)
|
require.Equal(t, err.Code(), codeType, "Err function expected to return proper code. tc #%d", i)
|
||||||
require.Equal(t, err.Codespace(), CodespaceRoot, "Err function expected to return proper codespace. tc #%d", i)
|
require.Equal(t, err.Codespace(), CodespaceRoot, "Err function expected to return proper codespace. tc #%d", i)
|
||||||
require.Equal(t, err.Result().Code, ToABCICode(CodespaceRoot, codeType), "Err function expected to return proper ABCICode. tc #%d")
|
require.Equal(t, err.QueryResult().Code, uint32(err.Code()), "Err function expected to return proper Code from QueryResult. tc #%d")
|
||||||
require.Equal(t, err.QueryResult().Code, uint32(err.ABCICode()), "Err function expected to return proper ABCICode from QueryResult. tc #%d")
|
|
||||||
require.Equal(t, err.QueryResult().Log, err.ABCILog(), "Err function expected to return proper ABCILog from QueryResult. tc #%d")
|
require.Equal(t, err.QueryResult().Log, err.ABCILog(), "Err function expected to return proper ABCILog from QueryResult. tc #%d")
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, ABCICodeOK, ToABCICode(CodespaceRoot, CodeOK))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAppendMsgToErr(t *testing.T) {
|
func TestAppendMsgToErr(t *testing.T) {
|
||||||
|
|
64
types/gas.go
64
types/gas.go
|
@ -18,17 +18,27 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Gas measured by the SDK
|
// Gas measured by the SDK
|
||||||
type Gas = int64
|
type Gas = uint64
|
||||||
|
|
||||||
// ErrorOutOfGas defines an error thrown when an action results in out of gas.
|
// ErrorOutOfGas defines an error thrown when an action results in out of gas.
|
||||||
type ErrorOutOfGas struct {
|
type ErrorOutOfGas struct {
|
||||||
Descriptor string
|
Descriptor string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrorGasOverflow defines an error thrown when an action results gas consumption
|
||||||
|
// unsigned integer overflow.
|
||||||
|
type ErrorGasOverflow struct {
|
||||||
|
Descriptor string
|
||||||
|
}
|
||||||
|
|
||||||
// GasMeter interface to track gas consumption
|
// GasMeter interface to track gas consumption
|
||||||
type GasMeter interface {
|
type GasMeter interface {
|
||||||
GasConsumed() Gas
|
GasConsumed() Gas
|
||||||
|
GasConsumedToLimit() Gas
|
||||||
|
Limit() Gas
|
||||||
ConsumeGas(amount Gas, descriptor string)
|
ConsumeGas(amount Gas, descriptor string)
|
||||||
|
IsPastLimit() bool
|
||||||
|
IsOutOfGas() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type basicGasMeter struct {
|
type basicGasMeter struct {
|
||||||
|
@ -48,13 +58,39 @@ func (g *basicGasMeter) GasConsumed() Gas {
|
||||||
return g.consumed
|
return g.consumed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *basicGasMeter) Limit() Gas {
|
||||||
|
return g.limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *basicGasMeter) GasConsumedToLimit() Gas {
|
||||||
|
if g.IsPastLimit() {
|
||||||
|
return g.limit
|
||||||
|
}
|
||||||
|
return g.consumed
|
||||||
|
}
|
||||||
|
|
||||||
func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) {
|
func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) {
|
||||||
g.consumed += amount
|
var overflow bool
|
||||||
|
|
||||||
|
// TODO: Should we set the consumed field after overflow checking?
|
||||||
|
g.consumed, overflow = AddUint64Overflow(g.consumed, amount)
|
||||||
|
if overflow {
|
||||||
|
panic(ErrorGasOverflow{descriptor})
|
||||||
|
}
|
||||||
|
|
||||||
if g.consumed > g.limit {
|
if g.consumed > g.limit {
|
||||||
panic(ErrorOutOfGas{descriptor})
|
panic(ErrorOutOfGas{descriptor})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *basicGasMeter) IsPastLimit() bool {
|
||||||
|
return g.consumed > g.limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *basicGasMeter) IsOutOfGas() bool {
|
||||||
|
return g.consumed >= g.limit
|
||||||
|
}
|
||||||
|
|
||||||
type infiniteGasMeter struct {
|
type infiniteGasMeter struct {
|
||||||
consumed Gas
|
consumed Gas
|
||||||
}
|
}
|
||||||
|
@ -70,8 +106,30 @@ func (g *infiniteGasMeter) GasConsumed() Gas {
|
||||||
return g.consumed
|
return g.consumed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *infiniteGasMeter) GasConsumedToLimit() Gas {
|
||||||
|
return g.consumed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *infiniteGasMeter) Limit() Gas {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
|
func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
|
||||||
g.consumed += amount
|
var overflow bool
|
||||||
|
|
||||||
|
// TODO: Should we set the consumed field after overflow checking?
|
||||||
|
g.consumed, overflow = AddUint64Overflow(g.consumed, amount)
|
||||||
|
if overflow {
|
||||||
|
panic(ErrorGasOverflow{descriptor})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *infiniteGasMeter) IsPastLimit() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *infiniteGasMeter) IsOutOfGas() bool {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GasConfig defines gas cost for each operation on KVStores
|
// GasConfig defines gas cost for each operation on KVStores
|
||||||
|
|
|
@ -21,15 +21,24 @@ func TestGasMeter(t *testing.T) {
|
||||||
|
|
||||||
for tcnum, tc := range cases {
|
for tcnum, tc := range cases {
|
||||||
meter := NewGasMeter(tc.limit)
|
meter := NewGasMeter(tc.limit)
|
||||||
used := int64(0)
|
used := uint64(0)
|
||||||
|
|
||||||
for unum, usage := range tc.usage {
|
for unum, usage := range tc.usage {
|
||||||
used += usage
|
used += usage
|
||||||
require.NotPanics(t, func() { meter.ConsumeGas(usage, "") }, "Not exceeded limit but panicked. tc #%d, usage #%d", tcnum, unum)
|
require.NotPanics(t, func() { meter.ConsumeGas(usage, "") }, "Not exceeded limit but panicked. tc #%d, usage #%d", tcnum, unum)
|
||||||
require.Equal(t, used, meter.GasConsumed(), "Gas consumption not match. tc #%d, usage #%d", tcnum, unum)
|
require.Equal(t, used, meter.GasConsumed(), "Gas consumption not match. tc #%d, usage #%d", tcnum, unum)
|
||||||
|
require.Equal(t, used, meter.GasConsumedToLimit(), "Gas consumption (to limit) not match. tc #%d, usage #%d", tcnum, unum)
|
||||||
|
require.False(t, meter.IsPastLimit(), "Not exceeded limit but got IsPastLimit() true")
|
||||||
|
if unum < len(tc.usage)-1 {
|
||||||
|
require.False(t, meter.IsOutOfGas(), "Not yet at limit but got IsOutOfGas() true")
|
||||||
|
} else {
|
||||||
|
require.True(t, meter.IsOutOfGas(), "At limit but got IsOutOfGas() false")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Panics(t, func() { meter.ConsumeGas(1, "") }, "Exceeded but not panicked. tc #%d", tcnum)
|
require.Panics(t, func() { meter.ConsumeGas(1, "") }, "Exceeded but not panicked. tc #%d", tcnum)
|
||||||
|
require.Equal(t, meter.GasConsumedToLimit(), meter.Limit(), "Gas consumption (to limit) not match limit")
|
||||||
|
require.Equal(t, meter.GasConsumed(), meter.Limit()+1, "Gas consumption not match limit+1")
|
||||||
break
|
break
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
53
types/int.go
53
types/int.go
|
@ -2,6 +2,7 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -321,11 +322,11 @@ func NewUint(n uint64) Uint {
|
||||||
|
|
||||||
// NewUintFromBigUint constructs Uint from big.Uint
|
// NewUintFromBigUint constructs Uint from big.Uint
|
||||||
func NewUintFromBigInt(i *big.Int) Uint {
|
func NewUintFromBigInt(i *big.Int) Uint {
|
||||||
// Check overflow
|
res := Uint{i}
|
||||||
if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 {
|
if UintOverflow(res) {
|
||||||
panic("Uint overflow")
|
panic("Uint overflow")
|
||||||
}
|
}
|
||||||
return Uint{i}
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUintFromString constructs Uint from string
|
// NewUintFromString constructs Uint from string
|
||||||
|
@ -352,11 +353,12 @@ func NewUintWithDecimal(n uint64, dec int) Uint {
|
||||||
i := new(big.Int)
|
i := new(big.Int)
|
||||||
i.Mul(new(big.Int).SetUint64(n), exp)
|
i.Mul(new(big.Int).SetUint64(n), exp)
|
||||||
|
|
||||||
// Check overflow
|
res := Uint{i}
|
||||||
if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 {
|
if UintOverflow(res) {
|
||||||
panic("NewUintWithDecimal() out of bound")
|
panic("NewUintWithDecimal() out of bound")
|
||||||
}
|
}
|
||||||
return Uint{i}
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZeroUint returns Uint value with zero
|
// ZeroUint returns Uint value with zero
|
||||||
|
@ -407,8 +409,7 @@ func (i Uint) LT(i2 Uint) bool {
|
||||||
// Add adds Uint from another
|
// Add adds Uint from another
|
||||||
func (i Uint) Add(i2 Uint) (res Uint) {
|
func (i Uint) Add(i2 Uint) (res Uint) {
|
||||||
res = Uint{add(i.i, i2.i)}
|
res = Uint{add(i.i, i2.i)}
|
||||||
// Check overflow
|
if UintOverflow(res) {
|
||||||
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
|
|
||||||
panic("Uint overflow")
|
panic("Uint overflow")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -422,13 +423,23 @@ func (i Uint) AddRaw(i2 uint64) Uint {
|
||||||
// Sub subtracts Uint from another
|
// Sub subtracts Uint from another
|
||||||
func (i Uint) Sub(i2 Uint) (res Uint) {
|
func (i Uint) Sub(i2 Uint) (res Uint) {
|
||||||
res = Uint{sub(i.i, i2.i)}
|
res = Uint{sub(i.i, i2.i)}
|
||||||
// Check overflow
|
if UintOverflow(res) {
|
||||||
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
|
|
||||||
panic("Uint overflow")
|
panic("Uint overflow")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SafeSub attempts to subtract one Uint from another. A boolean is also returned
|
||||||
|
// indicating if the result contains integer overflow.
|
||||||
|
func (i Uint) SafeSub(i2 Uint) (Uint, bool) {
|
||||||
|
res := Uint{sub(i.i, i2.i)}
|
||||||
|
if UintOverflow(res) {
|
||||||
|
return res, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, false
|
||||||
|
}
|
||||||
|
|
||||||
// SubRaw subtracts uint64 from Uint
|
// SubRaw subtracts uint64 from Uint
|
||||||
func (i Uint) SubRaw(i2 uint64) Uint {
|
func (i Uint) SubRaw(i2 uint64) Uint {
|
||||||
return i.Sub(NewUint(i2))
|
return i.Sub(NewUint(i2))
|
||||||
|
@ -436,15 +447,15 @@ func (i Uint) SubRaw(i2 uint64) Uint {
|
||||||
|
|
||||||
// Mul multiples two Uints
|
// Mul multiples two Uints
|
||||||
func (i Uint) Mul(i2 Uint) (res Uint) {
|
func (i Uint) Mul(i2 Uint) (res Uint) {
|
||||||
// Check overflow
|
|
||||||
if i.i.BitLen()+i2.i.BitLen()-1 > 256 {
|
if i.i.BitLen()+i2.i.BitLen()-1 > 256 {
|
||||||
panic("Uint overflow")
|
panic("Uint overflow")
|
||||||
}
|
}
|
||||||
|
|
||||||
res = Uint{mul(i.i, i2.i)}
|
res = Uint{mul(i.i, i2.i)}
|
||||||
// Check overflow
|
if UintOverflow(res) {
|
||||||
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
|
|
||||||
panic("Uint overflow")
|
panic("Uint overflow")
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,6 +540,22 @@ func (i *Uint) UnmarshalJSON(bz []byte) error {
|
||||||
|
|
||||||
//__________________________________________________________________________
|
//__________________________________________________________________________
|
||||||
|
|
||||||
|
// UintOverflow returns true if a given unsigned integer overflows and false
|
||||||
|
// otherwise.
|
||||||
|
func UintOverflow(x Uint) bool {
|
||||||
|
return x.i.Sign() == -1 || x.i.Sign() == 1 && x.i.BitLen() > 256
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUint64Overflow performs the addition operation on two uint64 integers and
|
||||||
|
// returns a boolean on whether or not the result overflows.
|
||||||
|
func AddUint64Overflow(a, b uint64) (uint64, bool) {
|
||||||
|
if math.MaxUint64-a < b {
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return a + b, false
|
||||||
|
}
|
||||||
|
|
||||||
// intended to be used with require/assert: require.True(IntEq(...))
|
// intended to be used with require/assert: require.True(IntEq(...))
|
||||||
func IntEq(t *testing.T, exp, got Int) (*testing.T, bool, string, string, string) {
|
func IntEq(t *testing.T, exp, got Int) (*testing.T, bool, string, string, string) {
|
||||||
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String()
|
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String()
|
||||||
|
|
|
@ -590,3 +590,53 @@ func TestEncodingTableUint(t *testing.T) {
|
||||||
require.Equal(t, tc.i, i, "Unmarshaled value is different from expected. tc #%d", tcnum)
|
require.Equal(t, tc.i, i, "Unmarshaled value is different from expected. tc #%d", tcnum)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSafeSub(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
x, y Uint
|
||||||
|
expected uint64
|
||||||
|
overflow bool
|
||||||
|
}{
|
||||||
|
{NewUint(0), NewUint(0), 0, false},
|
||||||
|
{NewUint(10), NewUint(5), 5, false},
|
||||||
|
{NewUint(5), NewUint(10), 5, true},
|
||||||
|
{NewUint(math.MaxUint64), NewUint(0), math.MaxUint64, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
res, overflow := tc.x.SafeSub(tc.y)
|
||||||
|
require.Equal(
|
||||||
|
t, tc.overflow, overflow,
|
||||||
|
"invalid overflow result; x: %s, y: %s, tc: #%d", tc.x, tc.y, i,
|
||||||
|
)
|
||||||
|
require.Equal(
|
||||||
|
t, tc.expected, res.BigInt().Uint64(),
|
||||||
|
"invalid subtraction result; x: %s, y: %s, tc: #%d", tc.x, tc.y, i,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddUint64Overflow(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
a, b uint64
|
||||||
|
result uint64
|
||||||
|
overflow bool
|
||||||
|
}{
|
||||||
|
{0, 0, 0, false},
|
||||||
|
{100, 100, 200, false},
|
||||||
|
{math.MaxUint64 / 2, math.MaxUint64/2 + 1, math.MaxUint64, false},
|
||||||
|
{math.MaxUint64 / 2, math.MaxUint64/2 + 2, 0, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
res, overflow := AddUint64Overflow(tc.a, tc.b)
|
||||||
|
require.Equal(
|
||||||
|
t, tc.overflow, overflow,
|
||||||
|
"invalid overflow result; tc: #%d, a: %d, b: %d", i, tc.a, tc.b,
|
||||||
|
)
|
||||||
|
require.Equal(
|
||||||
|
t, tc.result, res,
|
||||||
|
"invalid uint64 result; tc: #%d, a: %d, b: %d", i, tc.a, tc.b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModuleClients helps modules provide a standard interface for exporting client functionality
|
||||||
|
type ModuleClients interface {
|
||||||
|
GetQueryCmd() *cobra.Command
|
||||||
|
GetTxCmd() *cobra.Command
|
||||||
|
}
|
|
@ -4,7 +4,10 @@ package types
|
||||||
type Result struct {
|
type Result struct {
|
||||||
|
|
||||||
// Code is the response code, is stored back on the chain.
|
// Code is the response code, is stored back on the chain.
|
||||||
Code ABCICodeType
|
Code CodeType
|
||||||
|
|
||||||
|
// Codespace is the string referring to the domain of an error
|
||||||
|
Codespace CodespaceType
|
||||||
|
|
||||||
// Data is any data returned from the app.
|
// Data is any data returned from the app.
|
||||||
Data []byte
|
Data []byte
|
||||||
|
@ -13,10 +16,10 @@ type Result struct {
|
||||||
Log string
|
Log string
|
||||||
|
|
||||||
// GasWanted is the maximum units of work we allow this tx to perform.
|
// GasWanted is the maximum units of work we allow this tx to perform.
|
||||||
GasWanted int64
|
GasWanted uint64
|
||||||
|
|
||||||
// GasUsed is the amount of gas actually consumed. NOTE: unimplemented
|
// GasUsed is the amount of gas actually consumed. NOTE: unimplemented
|
||||||
GasUsed int64
|
GasUsed uint64
|
||||||
|
|
||||||
// Tx fee amount and denom.
|
// Tx fee amount and denom.
|
||||||
FeeAmount int64
|
FeeAmount int64
|
||||||
|
|
|
@ -13,6 +13,6 @@ func TestResult(t *testing.T) {
|
||||||
res.Data = []byte("data")
|
res.Data = []byte("data")
|
||||||
require.True(t, res.IsOK())
|
require.True(t, res.IsOK())
|
||||||
|
|
||||||
res.Code = ABCICodeType(1)
|
res.Code = CodeType(1)
|
||||||
require.False(t, res.IsOK())
|
require.False(t, res.IsOK())
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ type MultiStore interface { //nolint
|
||||||
CacheMultiStore() CacheMultiStore
|
CacheMultiStore() CacheMultiStore
|
||||||
|
|
||||||
// Convenience for fetching substores.
|
// Convenience for fetching substores.
|
||||||
|
// If the store does not exist, panics.
|
||||||
GetStore(StoreKey) Store
|
GetStore(StoreKey) Store
|
||||||
GetKVStore(StoreKey) KVStore
|
GetKVStore(StoreKey) KVStore
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,12 @@ type Msg interface {
|
||||||
|
|
||||||
// Transactions objects must fulfill the Tx
|
// Transactions objects must fulfill the Tx
|
||||||
type Tx interface {
|
type Tx interface {
|
||||||
|
// Gets the all the transaction's messages.
|
||||||
// Gets the Msg.
|
|
||||||
GetMsgs() []Msg
|
GetMsgs() []Msg
|
||||||
|
|
||||||
|
// ValidateBasic does a simple and lightweight validation check that doesn't
|
||||||
|
// require access to any other information.
|
||||||
|
ValidateBasic() Error
|
||||||
}
|
}
|
||||||
|
|
||||||
//__________________________________________________________
|
//__________________________________________________________
|
||||||
|
|
|
@ -21,11 +21,11 @@ type Account interface {
|
||||||
GetPubKey() crypto.PubKey // can return nil.
|
GetPubKey() crypto.PubKey // can return nil.
|
||||||
SetPubKey(crypto.PubKey) error
|
SetPubKey(crypto.PubKey) error
|
||||||
|
|
||||||
GetAccountNumber() int64
|
GetAccountNumber() uint64
|
||||||
SetAccountNumber(int64) error
|
SetAccountNumber(uint64) error
|
||||||
|
|
||||||
GetSequence() int64
|
GetSequence() uint64
|
||||||
SetSequence(int64) error
|
SetSequence(uint64) error
|
||||||
|
|
||||||
GetCoins() sdk.Coins
|
GetCoins() sdk.Coins
|
||||||
SetCoins(sdk.Coins) error
|
SetCoins(sdk.Coins) error
|
||||||
|
@ -48,8 +48,8 @@ type BaseAccount struct {
|
||||||
Address sdk.AccAddress `json:"address"`
|
Address sdk.AccAddress `json:"address"`
|
||||||
Coins sdk.Coins `json:"coins"`
|
Coins sdk.Coins `json:"coins"`
|
||||||
PubKey crypto.PubKey `json:"public_key"`
|
PubKey crypto.PubKey `json:"public_key"`
|
||||||
AccountNumber int64 `json:"account_number"`
|
AccountNumber uint64 `json:"account_number"`
|
||||||
Sequence int64 `json:"sequence"`
|
Sequence uint64 `json:"sequence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prototype function for BaseAccount
|
// Prototype function for BaseAccount
|
||||||
|
@ -100,23 +100,23 @@ func (acc *BaseAccount) SetCoins(coins sdk.Coins) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Account
|
// Implements Account
|
||||||
func (acc *BaseAccount) GetAccountNumber() int64 {
|
func (acc *BaseAccount) GetAccountNumber() uint64 {
|
||||||
return acc.AccountNumber
|
return acc.AccountNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Account
|
// Implements Account
|
||||||
func (acc *BaseAccount) SetAccountNumber(accNumber int64) error {
|
func (acc *BaseAccount) SetAccountNumber(accNumber uint64) error {
|
||||||
acc.AccountNumber = accNumber
|
acc.AccountNumber = accNumber
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements sdk.Account.
|
// Implements sdk.Account.
|
||||||
func (acc *BaseAccount) GetSequence() int64 {
|
func (acc *BaseAccount) GetSequence() uint64 {
|
||||||
return acc.Sequence
|
return acc.Sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements sdk.Account.
|
// Implements sdk.Account.
|
||||||
func (acc *BaseAccount) SetSequence(seq int64) error {
|
func (acc *BaseAccount) SetSequence(seq uint64) error {
|
||||||
acc.Sequence = seq
|
acc.Sequence = seq
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ func TestBaseAccountSequence(t *testing.T) {
|
||||||
_, _, addr := keyPubAddr()
|
_, _, addr := keyPubAddr()
|
||||||
acc := NewBaseAccountWithAddress(addr)
|
acc := NewBaseAccountWithAddress(addr)
|
||||||
|
|
||||||
seq := int64(7)
|
seq := uint64(7)
|
||||||
|
|
||||||
err := acc.SetSequence(seq)
|
err := acc.SetSequence(seq)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
@ -79,7 +79,7 @@ func TestBaseAccountMarshal(t *testing.T) {
|
||||||
acc := NewBaseAccountWithAddress(addr)
|
acc := NewBaseAccountWithAddress(addr)
|
||||||
|
|
||||||
someCoins := sdk.Coins{sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 246)}
|
someCoins := sdk.Coins{sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 246)}
|
||||||
seq := int64(7)
|
seq := uint64(7)
|
||||||
|
|
||||||
// set everything on the account
|
// set everything on the account
|
||||||
err := acc.SetPubKey(pub)
|
err := acc.SetPubKey(pub)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
"github.com/tendermint/tendermint/crypto/multisig"
|
|
||||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,27 +66,18 @@ func NewAnteHandler(am AccountKeeper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err := validateBasic(stdTx)
|
if err := tx.ValidateBasic(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return newCtx, err.Result(), true
|
return newCtx, err.Result(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
// charge gas for the memo
|
// charge gas for the memo
|
||||||
newCtx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo")
|
newCtx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo")
|
||||||
|
|
||||||
// stdSigs contains the sequence number, account number, and signatures
|
// stdSigs contains the sequence number, account number, and signatures.
|
||||||
stdSigs := stdTx.GetSignatures() // When simulating, this would just be a 0-length slice.
|
// When simulating, this would just be a 0-length slice.
|
||||||
|
stdSigs := stdTx.GetSignatures()
|
||||||
signerAddrs := stdTx.GetSigners()
|
signerAddrs := stdTx.GetSigners()
|
||||||
|
|
||||||
sigCount := 0
|
|
||||||
for i := 0; i < len(stdSigs); i++ {
|
|
||||||
sigCount += countSubKeys(stdSigs[i].PubKey)
|
|
||||||
if sigCount > txSigLimit {
|
|
||||||
return newCtx, sdk.ErrTooManySignatures(fmt.Sprintf(
|
|
||||||
"signatures: %d, limit: %d", sigCount, txSigLimit),
|
|
||||||
).Result(), true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the list of all sign bytes
|
// create the list of all sign bytes
|
||||||
signBytesList := getSignBytesList(newCtx.ChainID(), stdTx, stdSigs)
|
signBytesList := getSignBytesList(newCtx.ChainID(), stdTx, stdSigs)
|
||||||
signerAccs, res := getSignerAccs(newCtx, am, signerAddrs)
|
signerAccs, res := getSignerAccs(newCtx, am, signerAddrs)
|
||||||
|
@ -128,29 +118,6 @@ func NewAnteHandler(am AccountKeeper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the transaction based on things that don't depend on the context
|
|
||||||
func validateBasic(tx StdTx) (err sdk.Error) {
|
|
||||||
// Assert that there are signatures.
|
|
||||||
sigs := tx.GetSignatures()
|
|
||||||
if len(sigs) == 0 {
|
|
||||||
return sdk.ErrUnauthorized("no signers")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert that number of signatures is correct.
|
|
||||||
var signerAddrs = tx.GetSigners()
|
|
||||||
if len(sigs) != len(signerAddrs) {
|
|
||||||
return sdk.ErrUnauthorized("wrong number of signers")
|
|
||||||
}
|
|
||||||
|
|
||||||
memo := tx.GetMemo()
|
|
||||||
if len(memo) > maxMemoCharacters {
|
|
||||||
return sdk.ErrMemoTooLarge(
|
|
||||||
fmt.Sprintf("maximum number of characters is %d but received %d characters",
|
|
||||||
maxMemoCharacters, len(memo)))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSignerAccs(ctx sdk.Context, am AccountKeeper, addrs []sdk.AccAddress) (accs []Account, res sdk.Result) {
|
func getSignerAccs(ctx sdk.Context, am AccountKeeper, addrs []sdk.AccAddress) (accs []Account, res sdk.Result) {
|
||||||
accs = make([]Account, len(addrs))
|
accs = make([]Account, len(addrs))
|
||||||
for i := 0; i < len(accs); i++ {
|
for i := 0; i < len(accs); i++ {
|
||||||
|
@ -260,13 +227,16 @@ func consumeSignatureVerificationGas(meter sdk.GasMeter, pubkey crypto.PubKey) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func adjustFeesByGas(fees sdk.Coins, gas int64) sdk.Coins {
|
func adjustFeesByGas(fees sdk.Coins, gas uint64) sdk.Coins {
|
||||||
gasCost := gas / gasPerUnitCost
|
gasCost := gas / gasPerUnitCost
|
||||||
gasFees := make(sdk.Coins, len(fees))
|
gasFees := make(sdk.Coins, len(fees))
|
||||||
|
|
||||||
// TODO: Make this not price all coins in the same way
|
// TODO: Make this not price all coins in the same way
|
||||||
|
// TODO: Undo int64 casting once unsigned integers are supported for coins
|
||||||
for i := 0; i < len(fees); i++ {
|
for i := 0; i < len(fees); i++ {
|
||||||
gasFees[i] = sdk.NewInt64Coin(fees[i].Denom, gasCost)
|
gasFees[i] = sdk.NewInt64Coin(fees[i].Denom, int64(gasCost))
|
||||||
}
|
}
|
||||||
|
|
||||||
return fees.Plus(gasFees)
|
return fees.Plus(gasFees)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,23 +247,35 @@ func deductFees(acc Account, fee StdFee) (Account, sdk.Result) {
|
||||||
coins := acc.GetCoins()
|
coins := acc.GetCoins()
|
||||||
feeAmount := fee.Amount
|
feeAmount := fee.Amount
|
||||||
|
|
||||||
newCoins := coins.Minus(feeAmount)
|
if !feeAmount.IsValid() {
|
||||||
if !newCoins.IsNotNegative() {
|
return nil, sdk.ErrInsufficientFee(fmt.Sprintf("invalid fee amount: %s", feeAmount)).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
newCoins, ok := coins.SafeMinus(feeAmount)
|
||||||
|
if ok {
|
||||||
errMsg := fmt.Sprintf("%s < %s", coins, feeAmount)
|
errMsg := fmt.Sprintf("%s < %s", coins, feeAmount)
|
||||||
return nil, sdk.ErrInsufficientFunds(errMsg).Result()
|
return nil, sdk.ErrInsufficientFunds(errMsg).Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
err := acc.SetCoins(newCoins)
|
err := acc.SetCoins(newCoins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Handle w/ #870
|
// Handle w/ #870
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc, sdk.Result{}
|
return acc, sdk.Result{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureSufficientMempoolFees(ctx sdk.Context, stdTx StdTx) sdk.Result {
|
func ensureSufficientMempoolFees(ctx sdk.Context, stdTx StdTx) sdk.Result {
|
||||||
// currently we use a very primitive gas pricing model with a constant gasPrice.
|
// currently we use a very primitive gas pricing model with a constant gasPrice.
|
||||||
// adjustFeesByGas handles calculating the amount of fees required based on the provided gas.
|
// adjustFeesByGas handles calculating the amount of fees required based on the provided gas.
|
||||||
// TODO: Make the gasPrice not a constant, and account for tx size.
|
//
|
||||||
|
// TODO:
|
||||||
|
// - Make the gasPrice not a constant, and account for tx size.
|
||||||
|
// - Make Gas an unsigned integer and use tx basic validation
|
||||||
|
if stdTx.Fee.Gas <= 0 {
|
||||||
|
return sdk.ErrInternal(fmt.Sprintf("invalid gas supplied: %d", stdTx.Fee.Gas)).Result()
|
||||||
|
}
|
||||||
requiredFees := adjustFeesByGas(ctx.MinimumFees(), stdTx.Fee.Gas)
|
requiredFees := adjustFeesByGas(ctx.MinimumFees(), stdTx.Fee.Gas)
|
||||||
|
|
||||||
// NOTE: !A.IsAllGTE(B) is not the same as A.IsAllLT(B).
|
// NOTE: !A.IsAllGTE(B) is not the same as A.IsAllLT(B).
|
||||||
|
@ -306,10 +288,12 @@ func ensureSufficientMempoolFees(ctx sdk.Context, stdTx StdTx) sdk.Result {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setGasMeter(simulate bool, ctx sdk.Context, stdTx StdTx) sdk.Context {
|
func setGasMeter(simulate bool, ctx sdk.Context, stdTx StdTx) sdk.Context {
|
||||||
// set the gas meter
|
// In various cases such as simulation and during the genesis block, we do not
|
||||||
|
// meter any gas utilization.
|
||||||
if simulate || ctx.BlockHeight() == 0 {
|
if simulate || ctx.BlockHeight() == 0 {
|
||||||
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
|
return ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,15 +306,3 @@ func getSignBytesList(chainID string, stdTx StdTx, stdSigs []StdSignature) (sign
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func countSubKeys(pub crypto.PubKey) int {
|
|
||||||
v, ok := pub.(*multisig.PubKeyMultisigThreshold)
|
|
||||||
if !ok {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
nkeys := 0
|
|
||||||
for _, subkey := range v.PubKeys {
|
|
||||||
nkeys += countSubKeys(subkey)
|
|
||||||
}
|
|
||||||
return nkeys
|
|
||||||
}
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ func privAndAddr() (crypto.PrivKey, sdk.AccAddress) {
|
||||||
func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool) {
|
func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool) {
|
||||||
_, result, abort := anteHandler(ctx, tx, simulate)
|
_, result, abort := anteHandler(ctx, tx, simulate)
|
||||||
require.False(t, abort)
|
require.False(t, abort)
|
||||||
require.Equal(t, sdk.ABCICodeOK, result.Code)
|
require.Equal(t, sdk.CodeOK, result.Code)
|
||||||
require.True(t, result.IsOK())
|
require.True(t, result.IsOK())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +51,9 @@ func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx
|
||||||
func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool, code sdk.CodeType) {
|
func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool, code sdk.CodeType) {
|
||||||
newCtx, result, abort := anteHandler(ctx, tx, simulate)
|
newCtx, result, abort := anteHandler(ctx, tx, simulate)
|
||||||
require.True(t, abort)
|
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))
|
require.Equal(t, code, result.Code, fmt.Sprintf("Expected %v, got %v", code, result))
|
||||||
|
require.Equal(t, sdk.CodespaceRoot, result.Codespace)
|
||||||
|
|
||||||
if code == sdk.CodeOutOfGas {
|
if code == sdk.CodeOutOfGas {
|
||||||
stdTx, ok := tx.(StdTx)
|
stdTx, ok := tx.(StdTx)
|
||||||
|
@ -65,7 +66,7 @@ func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee) sdk.Tx {
|
func newTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums []uint64, seqs []uint64, fee StdFee) sdk.Tx {
|
||||||
sigs := make([]StdSignature, len(privs))
|
sigs := make([]StdSignature, len(privs))
|
||||||
for i, priv := range privs {
|
for i, priv := range privs {
|
||||||
signBytes := StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, "")
|
signBytes := StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, "")
|
||||||
|
@ -79,7 +80,7 @@ func newTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee, memo string) sdk.Tx {
|
func newTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums []uint64, seqs []uint64, fee StdFee, memo string) sdk.Tx {
|
||||||
sigs := make([]StdSignature, len(privs))
|
sigs := make([]StdSignature, len(privs))
|
||||||
for i, priv := range privs {
|
for i, priv := range privs {
|
||||||
signBytes := StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, memo)
|
signBytes := StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, memo)
|
||||||
|
@ -94,7 +95,7 @@ func newTestTxWithMemo(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
// All signers sign over the same StdSignDoc. Should always create invalid signatures
|
// All signers sign over the same StdSignDoc. Should always create invalid signatures
|
||||||
func newTestTxWithSignBytes(msgs []sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee, signBytes []byte, memo string) sdk.Tx {
|
func newTestTxWithSignBytes(msgs []sdk.Msg, privs []crypto.PrivKey, accNums []uint64, seqs []uint64, fee StdFee, signBytes []byte, memo string) sdk.Tx {
|
||||||
sigs := make([]StdSignature, len(privs))
|
sigs := make([]StdSignature, len(privs))
|
||||||
for i, priv := range privs {
|
for i, priv := range privs {
|
||||||
sig, err := priv.Sign(signBytes)
|
sig, err := priv.Sign(signBytes)
|
||||||
|
@ -132,7 +133,7 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
||||||
msgs := []sdk.Msg{msg1, msg2}
|
msgs := []sdk.Msg{msg1, msg2}
|
||||||
|
|
||||||
// test no signatures
|
// test no signatures
|
||||||
privs, accNums, seqs := []crypto.PrivKey{}, []int64{}, []int64{}
|
privs, accNums, seqs := []crypto.PrivKey{}, []uint64{}, []uint64{}
|
||||||
tx = newTestTx(ctx, msgs, privs, accNums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accNums, seqs, fee)
|
||||||
|
|
||||||
// tx.GetSigners returns addresses in correct order: addr1, addr2, addr3
|
// tx.GetSigners returns addresses in correct order: addr1, addr2, addr3
|
||||||
|
@ -144,12 +145,12 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
||||||
|
|
||||||
// test num sigs dont match GetSigners
|
// test num sigs dont match GetSigners
|
||||||
privs, accNums, seqs = []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
privs, accNums, seqs = []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accNums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accNums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
||||||
|
|
||||||
// test an unrecognized account
|
// test an unrecognized account
|
||||||
privs, accNums, seqs = []crypto.PrivKey{priv1, priv2, priv3}, []int64{0, 1, 2}, []int64{0, 0, 0}
|
privs, accNums, seqs = []crypto.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accNums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accNums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnknownAddress)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnknownAddress)
|
||||||
|
|
||||||
|
@ -192,30 +193,30 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
|
||||||
msgs := []sdk.Msg{msg}
|
msgs := []sdk.Msg{msg}
|
||||||
|
|
||||||
// test good tx from one signer
|
// test good tx from one signer
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
// new tx from wrong account number
|
// new tx from wrong account number
|
||||||
seqs = []int64{1}
|
seqs = []uint64{1}
|
||||||
tx = newTestTx(ctx, msgs, privs, []int64{1}, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
// from correct account number
|
// from correct account number
|
||||||
seqs = []int64{1}
|
seqs = []uint64{1}
|
||||||
tx = newTestTx(ctx, msgs, privs, []int64{0}, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, []uint64{0}, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
// new tx with another signer and incorrect account numbers
|
// new tx with another signer and incorrect account numbers
|
||||||
msg1 := newTestMsg(addr1, addr2)
|
msg1 := newTestMsg(addr1, addr2)
|
||||||
msg2 := newTestMsg(addr2, addr1)
|
msg2 := newTestMsg(addr2, addr1)
|
||||||
msgs = []sdk.Msg{msg1, msg2}
|
msgs = []sdk.Msg{msg1, msg2}
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{1, 0}, []int64{2, 0}
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{1, 0}, []uint64{2, 0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
// correct account numbers
|
// correct account numbers
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{2, 0}
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{2, 0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
}
|
}
|
||||||
|
@ -252,30 +253,30 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) {
|
||||||
msgs := []sdk.Msg{msg}
|
msgs := []sdk.Msg{msg}
|
||||||
|
|
||||||
// test good tx from one signer
|
// test good tx from one signer
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
// new tx from wrong account number
|
// new tx from wrong account number
|
||||||
seqs = []int64{1}
|
seqs = []uint64{1}
|
||||||
tx = newTestTx(ctx, msgs, privs, []int64{1}, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
// from correct account number
|
// from correct account number
|
||||||
seqs = []int64{1}
|
seqs = []uint64{1}
|
||||||
tx = newTestTx(ctx, msgs, privs, []int64{0}, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, []uint64{0}, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
// new tx with another signer and incorrect account numbers
|
// new tx with another signer and incorrect account numbers
|
||||||
msg1 := newTestMsg(addr1, addr2)
|
msg1 := newTestMsg(addr1, addr2)
|
||||||
msg2 := newTestMsg(addr2, addr1)
|
msg2 := newTestMsg(addr2, addr1)
|
||||||
msgs = []sdk.Msg{msg1, msg2}
|
msgs = []sdk.Msg{msg1, msg2}
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{1, 0}, []int64{2, 0}
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{1, 0}, []uint64{2, 0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
// correct account numbers
|
// correct account numbers
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 0}, []int64{2, 0}
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 0}, []uint64{2, 0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
}
|
}
|
||||||
|
@ -316,7 +317,7 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||||
msgs := []sdk.Msg{msg}
|
msgs := []sdk.Msg{msg}
|
||||||
|
|
||||||
// test good tx from one signer
|
// test good tx from one signer
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
|
@ -324,7 +325,7 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
// fix sequence, should pass
|
// fix sequence, should pass
|
||||||
seqs = []int64{1}
|
seqs = []uint64{1}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
|
@ -333,7 +334,7 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||||
msg2 := newTestMsg(addr3, addr1)
|
msg2 := newTestMsg(addr3, addr1)
|
||||||
msgs = []sdk.Msg{msg1, msg2}
|
msgs = []sdk.Msg{msg1, msg2}
|
||||||
|
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2, priv3}, []int64{0, 1, 2}, []int64{2, 0, 0}
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{2, 0, 0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
|
@ -343,18 +344,18 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||||
// tx from just second signer with incorrect sequence fails
|
// tx from just second signer with incorrect sequence fails
|
||||||
msg = newTestMsg(addr2)
|
msg = newTestMsg(addr2)
|
||||||
msgs = []sdk.Msg{msg}
|
msgs = []sdk.Msg{msg}
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv2}, []int64{1}, []int64{0}
|
privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{1}, []uint64{0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||||
|
|
||||||
// fix the sequence and it passes
|
// fix the sequence and it passes
|
||||||
tx = newTestTx(ctx, msgs, []crypto.PrivKey{priv2}, []int64{1}, []int64{1}, fee)
|
tx = newTestTx(ctx, msgs, []crypto.PrivKey{priv2}, []uint64{1}, []uint64{1}, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
// another tx from both of them that passes
|
// another tx from both of them that passes
|
||||||
msg = newTestMsg(addr1, addr2)
|
msg = newTestMsg(addr1, addr2)
|
||||||
msgs = []sdk.Msg{msg}
|
msgs = []sdk.Msg{msg}
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{3, 2}
|
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{3, 2}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
}
|
}
|
||||||
|
@ -380,7 +381,7 @@ func TestAnteHandlerFees(t *testing.T) {
|
||||||
// msg and signatures
|
// msg and signatures
|
||||||
var tx sdk.Tx
|
var tx sdk.Tx
|
||||||
msg := newTestMsg(addr1)
|
msg := newTestMsg(addr1)
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||||
fee := newStdFee()
|
fee := newStdFee()
|
||||||
msgs := []sdk.Msg{msg}
|
msgs := []sdk.Msg{msg}
|
||||||
|
|
||||||
|
@ -423,7 +424,7 @@ func TestAnteHandlerMemoGas(t *testing.T) {
|
||||||
// msg and signatures
|
// msg and signatures
|
||||||
var tx sdk.Tx
|
var tx sdk.Tx
|
||||||
msg := newTestMsg(addr1)
|
msg := newTestMsg(addr1)
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||||
fee := NewStdFee(0, sdk.NewInt64Coin("atom", 0))
|
fee := NewStdFee(0, sdk.NewInt64Coin("atom", 0))
|
||||||
|
|
||||||
// tx does not have enough gas
|
// tx does not have enough gas
|
||||||
|
@ -482,19 +483,19 @@ func TestAnteHandlerMultiSigner(t *testing.T) {
|
||||||
fee := newStdFee()
|
fee := newStdFee()
|
||||||
|
|
||||||
// signers in order
|
// signers in order
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1, priv2, priv3}, []int64{0, 1, 2}, []int64{0, 0, 0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}
|
||||||
tx = newTestTxWithMemo(ctx, msgs, privs, accnums, seqs, fee, "Check signers are in expected order and different account numbers works")
|
tx = newTestTxWithMemo(ctx, msgs, privs, accnums, seqs, fee, "Check signers are in expected order and different account numbers works")
|
||||||
|
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
// change sequence numbers
|
// change sequence numbers
|
||||||
tx = newTestTx(ctx, []sdk.Msg{msg1}, []crypto.PrivKey{priv1, priv2}, []int64{0, 1}, []int64{1, 1}, fee)
|
tx = newTestTx(ctx, []sdk.Msg{msg1}, []crypto.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{1, 1}, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
tx = newTestTx(ctx, []sdk.Msg{msg2}, []crypto.PrivKey{priv3, priv1}, []int64{2, 0}, []int64{1, 2}, fee)
|
tx = newTestTx(ctx, []sdk.Msg{msg2}, []crypto.PrivKey{priv3, priv1}, []uint64{2, 0}, []uint64{1, 2}, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
// expected seqs = [3, 2, 2]
|
// expected seqs = [3, 2, 2]
|
||||||
tx = newTestTxWithMemo(ctx, msgs, privs, accnums, []int64{3, 2, 2}, fee, "Check signers are in expected order and different account numbers and sequence numbers works")
|
tx = newTestTxWithMemo(ctx, msgs, privs, accnums, []uint64{3, 2, 2}, fee, "Check signers are in expected order and different account numbers and sequence numbers works")
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +532,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||||
fee3.Amount[0].Amount = fee3.Amount[0].Amount.AddRaw(100)
|
fee3.Amount[0].Amount = fee3.Amount[0].Amount.AddRaw(100)
|
||||||
|
|
||||||
// test good tx and signBytes
|
// test good tx and signBytes
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
|
||||||
|
@ -541,8 +542,8 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
chainID string
|
chainID string
|
||||||
accnum int64
|
accnum uint64
|
||||||
seq int64
|
seq uint64
|
||||||
fee StdFee
|
fee StdFee
|
||||||
msgs []sdk.Msg
|
msgs []sdk.Msg
|
||||||
code sdk.CodeType
|
code sdk.CodeType
|
||||||
|
@ -555,7 +556,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||||
{chainID, 0, 1, fee3, msgs, codeUnauth}, // test wrong fee
|
{chainID, 0, 1, fee3, msgs, codeUnauth}, // test wrong fee
|
||||||
}
|
}
|
||||||
|
|
||||||
privs, seqs = []crypto.PrivKey{priv1}, []int64{1}
|
privs, seqs = []crypto.PrivKey{priv1}, []uint64{1}
|
||||||
for _, cs := range cases {
|
for _, cs := range cases {
|
||||||
tx := newTestTxWithSignBytes(
|
tx := newTestTxWithSignBytes(
|
||||||
|
|
||||||
|
@ -567,14 +568,14 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// test wrong signer if public key exist
|
// test wrong signer if public key exist
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv2}, []int64{0}, []int64{1}
|
privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{0}, []uint64{1}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
||||||
|
|
||||||
// test wrong signer if public doesn't exist
|
// test wrong signer if public doesn't exist
|
||||||
msg = newTestMsg(addr2)
|
msg = newTestMsg(addr2)
|
||||||
msgs = []sdk.Msg{msg}
|
msgs = []sdk.Msg{msg}
|
||||||
privs, accnums, seqs = []crypto.PrivKey{priv1}, []int64{1}, []int64{0}
|
privs, accnums, seqs = []crypto.PrivKey{priv1}, []uint64{1}, []uint64{0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)
|
||||||
|
|
||||||
|
@ -608,7 +609,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||||
// test good tx and set public key
|
// test good tx and set public key
|
||||||
msg := newTestMsg(addr1)
|
msg := newTestMsg(addr1)
|
||||||
msgs := []sdk.Msg{msg}
|
msgs := []sdk.Msg{msg}
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
privs, accnums, seqs := []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||||
fee := newStdFee()
|
fee := newStdFee()
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||||
|
@ -619,7 +620,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||||
// test public key not found
|
// test public key not found
|
||||||
msg = newTestMsg(addr2)
|
msg = newTestMsg(addr2)
|
||||||
msgs = []sdk.Msg{msg}
|
msgs = []sdk.Msg{msg}
|
||||||
tx = newTestTx(ctx, msgs, privs, []int64{1}, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee)
|
||||||
sigs := tx.(StdTx).GetSignatures()
|
sigs := tx.(StdTx).GetSignatures()
|
||||||
sigs[0].PubKey = nil
|
sigs[0].PubKey = nil
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)
|
||||||
|
@ -628,7 +629,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||||
require.Nil(t, acc2.GetPubKey())
|
require.Nil(t, acc2.GetPubKey())
|
||||||
|
|
||||||
// test invalid signature and public key
|
// test invalid signature and public key
|
||||||
tx = newTestTx(ctx, msgs, privs, []int64{1}, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)
|
||||||
|
|
||||||
acc2 = mapper.GetAccount(ctx, addr2)
|
acc2 = mapper.GetAccount(ctx, addr2)
|
||||||
|
@ -676,7 +677,7 @@ func TestConsumeSignatureVerificationGas(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
gasConsumed int64
|
gasConsumed uint64
|
||||||
wantPanic bool
|
wantPanic bool
|
||||||
}{
|
}{
|
||||||
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), ed25519.GenPrivKey().PubKey()}, ed25519VerifyCost, false},
|
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), ed25519.GenPrivKey().PubKey()}, ed25519VerifyCost, false},
|
||||||
|
@ -698,7 +699,7 @@ func TestConsumeSignatureVerificationGas(t *testing.T) {
|
||||||
func TestAdjustFeesByGas(t *testing.T) {
|
func TestAdjustFeesByGas(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
fee sdk.Coins
|
fee sdk.Coins
|
||||||
gas int64
|
gas uint64
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -707,7 +708,6 @@ func TestAdjustFeesByGas(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{"nil coins", args{sdk.Coins{}, 10000}, sdk.Coins{}},
|
{"nil coins", args{sdk.Coins{}, 10000}, sdk.Coins{}},
|
||||||
{"nil coins", args{sdk.Coins{sdk.NewInt64Coin("A", 10), sdk.NewInt64Coin("B", 0)}, 10000}, sdk.Coins{sdk.NewInt64Coin("A", 20), sdk.NewInt64Coin("B", 10)}},
|
{"nil coins", args{sdk.Coins{sdk.NewInt64Coin("A", 10), sdk.NewInt64Coin("B", 0)}, 10000}, sdk.Coins{sdk.NewInt64Coin("A", 20), sdk.NewInt64Coin("B", 10)}},
|
||||||
{"negative coins", args{sdk.Coins{sdk.NewInt64Coin("A", -10), sdk.NewInt64Coin("B", 10)}, 10000}, sdk.Coins{sdk.NewInt64Coin("B", 20)}},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -785,7 +785,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) {
|
||||||
|
|
||||||
// test rejection logic
|
// test rejection logic
|
||||||
privs, accnums, seqs := []crypto.PrivKey{priv1, priv2, priv3, priv4, priv5, priv6, priv7, priv8},
|
privs, accnums, seqs := []crypto.PrivKey{priv1, priv2, priv3, priv4, priv5, priv6, priv7, priv8},
|
||||||
[]int64{0, 0, 0, 0, 0, 0, 0, 0}, []int64{0, 0, 0, 0, 0, 0, 0, 0}
|
[]uint64{0, 0, 0, 0, 0, 0, 0, 0}, []uint64{0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeTooManySignatures)
|
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeTooManySignatures)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,34 +5,17 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetAccountCmdDefault invokes the GetAccountCmd for the auth.BaseAccount type.
|
|
||||||
func GetAccountCmdDefault(storeName string, cdc *codec.Codec) *cobra.Command {
|
|
||||||
return GetAccountCmd(storeName, cdc, GetAccountDecoder(cdc))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccountDecoder gets the account decoder for auth.DefaultAccount.
|
|
||||||
func GetAccountDecoder(cdc *codec.Codec) auth.AccountDecoder {
|
|
||||||
return func(accBytes []byte) (acct auth.Account, err error) {
|
|
||||||
err = cdc.UnmarshalBinaryBare(accBytes, &acct)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return acct, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAccountCmd returns a query account that will display the state of the
|
// GetAccountCmd returns a query account that will display the state of the
|
||||||
// account at a given address.
|
// account at a given address.
|
||||||
// nolint: unparam
|
// nolint: unparam
|
||||||
func GetAccountCmd(storeName string, cdc *codec.Codec, decoder auth.AccountDecoder) *cobra.Command {
|
func GetAccountCmd(storeName string, cdc *codec.Codec) *cobra.Command {
|
||||||
return &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "account [address]",
|
Use: "account [address]",
|
||||||
Short: "Query account balance",
|
Short: "Query account balance",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
|
@ -47,9 +30,9 @@ func GetAccountCmd(storeName string, cdc *codec.Codec, decoder auth.AccountDecod
|
||||||
|
|
||||||
cliCtx := context.NewCLIContext().
|
cliCtx := context.NewCLIContext().
|
||||||
WithCodec(cdc).
|
WithCodec(cdc).
|
||||||
WithAccountDecoder(decoder)
|
WithAccountDecoder(cdc)
|
||||||
|
|
||||||
if err := cliCtx.EnsureAccountExistsFromAddr(key); err != nil {
|
if err = cliCtx.EnsureAccountExistsFromAddr(key); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,4 +55,7 @@ func GetAccountCmd(storeName string, cdc *codec.Codec, decoder auth.AccountDecod
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the flags here and return the command
|
||||||
|
return client.GetCommands(cmd)[0]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,8 @@ package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
@ -12,7 +11,9 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"github.com/tendermint/go-amino"
|
"github.com/tendermint/go-amino"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,10 +22,11 @@ const (
|
||||||
flagValidateSigs = "validate-signatures"
|
flagValidateSigs = "validate-signatures"
|
||||||
flagOffline = "offline"
|
flagOffline = "offline"
|
||||||
flagSigOnly = "signature-only"
|
flagSigOnly = "signature-only"
|
||||||
|
flagOutfile = "output-document"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetSignCommand returns the sign command
|
// GetSignCommand returns the sign command
|
||||||
func GetSignCommand(codec *amino.Codec, decoder auth.AccountDecoder) *cobra.Command {
|
func GetSignCommand(codec *amino.Codec) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "sign <file>",
|
Use: "sign <file>",
|
||||||
Short: "Sign transactions generated offline",
|
Short: "Sign transactions generated offline",
|
||||||
|
@ -41,7 +43,7 @@ order.
|
||||||
The --offline flag makes sure that the client will not reach out to the local cache.
|
The --offline flag makes sure that the client will not reach out to the local cache.
|
||||||
Thus account number or sequence number lookups will not be performed and it is
|
Thus account number or sequence number lookups will not be performed and it is
|
||||||
recommended to set such parameters manually.`,
|
recommended to set such parameters manually.`,
|
||||||
RunE: makeSignCmd(codec, decoder),
|
RunE: makeSignCmd(codec),
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
}
|
}
|
||||||
cmd.Flags().String(client.FlagName, "", "Name of private key with which to sign")
|
cmd.Flags().String(client.FlagName, "", "Name of private key with which to sign")
|
||||||
|
@ -51,10 +53,14 @@ recommended to set such parameters manually.`,
|
||||||
cmd.Flags().Bool(flagValidateSigs, false, "Print the addresses that must sign the transaction, "+
|
cmd.Flags().Bool(flagValidateSigs, false, "Print the addresses that must sign the transaction, "+
|
||||||
"those who have already signed it, and make sure that signatures are in the correct order.")
|
"those who have already signed it, and make sure that signatures are in the correct order.")
|
||||||
cmd.Flags().Bool(flagOffline, false, "Offline mode. Do not query local cache.")
|
cmd.Flags().Bool(flagOffline, false, "Offline mode. Do not query local cache.")
|
||||||
return cmd
|
cmd.Flags().String(flagOutfile, "",
|
||||||
|
"The document will be written to the given file instead of STDOUT")
|
||||||
|
|
||||||
|
// Add the flags here and return the command
|
||||||
|
return client.PostCommands(cmd)[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.Command, args []string) error {
|
func makeSignCmd(cdc *amino.Codec) func(cmd *cobra.Command, args []string) error {
|
||||||
return func(cmd *cobra.Command, args []string) (err error) {
|
return func(cmd *cobra.Command, args []string) (err error) {
|
||||||
stdTx, err := readAndUnmarshalStdTx(cdc, args[0])
|
stdTx, err := readAndUnmarshalStdTx(cdc, args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -72,7 +78,7 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return errors.New("required flag \"name\" has not been set")
|
return errors.New("required flag \"name\" has not been set")
|
||||||
}
|
}
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(decoder)
|
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(cdc)
|
||||||
txBldr := authtxb.NewTxBuilderFromCLI()
|
txBldr := authtxb.NewTxBuilderFromCLI()
|
||||||
|
|
||||||
// if --signature-only is on, then override --append
|
// if --signature-only is on, then override --append
|
||||||
|
@ -104,7 +110,20 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("%s\n", json)
|
|
||||||
|
if viper.GetString(flagOutfile) == "" {
|
||||||
|
fmt.Printf("%s\n", json)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fp, err := os.OpenFile(
|
||||||
|
viper.GetString(flagOutfile), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fp.Close()
|
||||||
|
fmt.Fprintf(fp, "%s\n", json)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
@ -17,11 +16,11 @@ import (
|
||||||
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, storeName string) {
|
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, storeName string) {
|
||||||
r.HandleFunc(
|
r.HandleFunc(
|
||||||
"/auth/accounts/{address}",
|
"/auth/accounts/{address}",
|
||||||
QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx),
|
QueryAccountRequestHandlerFn(storeName, cdc, context.GetAccountDecoder(cdc), cliCtx),
|
||||||
).Methods("GET")
|
).Methods("GET")
|
||||||
r.HandleFunc(
|
r.HandleFunc(
|
||||||
"/bank/balances/{address}",
|
"/bank/balances/{address}",
|
||||||
QueryBalancesRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx),
|
QueryBalancesRequestHandlerFn(storeName, cdc, context.GetAccountDecoder(cdc), cliCtx),
|
||||||
).Methods("GET")
|
).Methods("GET")
|
||||||
r.HandleFunc(
|
r.HandleFunc(
|
||||||
"/tx/sign",
|
"/tx/sign",
|
||||||
|
|
|
@ -18,8 +18,8 @@ type SignBody struct {
|
||||||
LocalAccountName string `json:"name"`
|
LocalAccountName string `json:"name"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
ChainID string `json:"chain_id"`
|
ChainID string `json:"chain_id"`
|
||||||
AccountNumber int64 `json:"account_number"`
|
AccountNumber uint64 `json:"account_number"`
|
||||||
Sequence int64 `json:"sequence"`
|
Sequence uint64 `json:"sequence"`
|
||||||
AppendSig bool `json:"append_sig"`
|
AppendSig bool `json:"append_sig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
// it is signed. For use in the CLI.
|
// it is signed. For use in the CLI.
|
||||||
type StdSignMsg struct {
|
type StdSignMsg struct {
|
||||||
ChainID string `json:"chain_id"`
|
ChainID string `json:"chain_id"`
|
||||||
AccountNumber int64 `json:"account_number"`
|
AccountNumber uint64 `json:"account_number"`
|
||||||
Sequence int64 `json:"sequence"`
|
Sequence uint64 `json:"sequence"`
|
||||||
Fee auth.StdFee `json:"fee"`
|
Fee auth.StdFee `json:"fee"`
|
||||||
Msgs []sdk.Msg `json:"msgs"`
|
Msgs []sdk.Msg `json:"msgs"`
|
||||||
Memo string `json:"memo"`
|
Memo string `json:"memo"`
|
||||||
|
|
|
@ -14,9 +14,9 @@ import (
|
||||||
// TxBuilder implements a transaction context created in SDK modules.
|
// TxBuilder implements a transaction context created in SDK modules.
|
||||||
type TxBuilder struct {
|
type TxBuilder struct {
|
||||||
Codec *codec.Codec
|
Codec *codec.Codec
|
||||||
AccountNumber int64
|
AccountNumber uint64
|
||||||
Sequence int64
|
Sequence uint64
|
||||||
Gas int64 // TODO: should this turn into uint64? requires further discussion - see #2173
|
Gas uint64
|
||||||
GasAdjustment float64
|
GasAdjustment float64
|
||||||
SimulateGas bool
|
SimulateGas bool
|
||||||
ChainID string
|
ChainID string
|
||||||
|
@ -38,10 +38,10 @@ func NewTxBuilderFromCLI() TxBuilder {
|
||||||
|
|
||||||
return TxBuilder{
|
return TxBuilder{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
|
AccountNumber: uint64(viper.GetInt64(client.FlagAccountNumber)),
|
||||||
Gas: client.GasFlagVar.Gas,
|
Gas: client.GasFlagVar.Gas,
|
||||||
GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment),
|
GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment),
|
||||||
Sequence: viper.GetInt64(client.FlagSequence),
|
Sequence: uint64(viper.GetInt64(client.FlagSequence)),
|
||||||
SimulateGas: client.GasFlagVar.Simulate,
|
SimulateGas: client.GasFlagVar.Simulate,
|
||||||
Fee: viper.GetString(client.FlagFee),
|
Fee: viper.GetString(client.FlagFee),
|
||||||
Memo: viper.GetString(client.FlagMemo),
|
Memo: viper.GetString(client.FlagMemo),
|
||||||
|
@ -61,7 +61,7 @@ func (bldr TxBuilder) WithChainID(chainID string) TxBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithGas returns a copy of the context with an updated gas.
|
// WithGas returns a copy of the context with an updated gas.
|
||||||
func (bldr TxBuilder) WithGas(gas int64) TxBuilder {
|
func (bldr TxBuilder) WithGas(gas uint64) TxBuilder {
|
||||||
bldr.Gas = gas
|
bldr.Gas = gas
|
||||||
return bldr
|
return bldr
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func (bldr TxBuilder) WithFee(fee string) TxBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSequence returns a copy of the context with an updated sequence number.
|
// WithSequence returns a copy of the context with an updated sequence number.
|
||||||
func (bldr TxBuilder) WithSequence(sequence int64) TxBuilder {
|
func (bldr TxBuilder) WithSequence(sequence uint64) TxBuilder {
|
||||||
bldr.Sequence = sequence
|
bldr.Sequence = sequence
|
||||||
return bldr
|
return bldr
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ func (bldr TxBuilder) WithMemo(memo string) TxBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithAccountNumber returns a copy of the context with an account number.
|
// WithAccountNumber returns a copy of the context with an account number.
|
||||||
func (bldr TxBuilder) WithAccountNumber(accnum int64) TxBuilder {
|
func (bldr TxBuilder) WithAccountNumber(accnum uint64) TxBuilder {
|
||||||
bldr.AccountNumber = accnum
|
bldr.AccountNumber = accnum
|
||||||
return bldr
|
return bldr
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
|
||||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||||
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -21,9 +21,9 @@ var (
|
||||||
func TestTxBuilderBuild(t *testing.T) {
|
func TestTxBuilderBuild(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
Codec *codec.Codec
|
Codec *codec.Codec
|
||||||
AccountNumber int64
|
AccountNumber uint64
|
||||||
Sequence int64
|
Sequence uint64
|
||||||
Gas int64
|
Gas uint64
|
||||||
GasAdjustment float64
|
GasAdjustment float64
|
||||||
SimulateGas bool
|
SimulateGas bool
|
||||||
ChainID string
|
ChainID string
|
||||||
|
|
|
@ -118,7 +118,7 @@ func (am AccountKeeper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the Sequence of the account at address
|
// Returns the Sequence of the account at address
|
||||||
func (am AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (int64, sdk.Error) {
|
func (am AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (uint64, sdk.Error) {
|
||||||
acc := am.GetAccount(ctx, addr)
|
acc := am.GetAccount(ctx, addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return 0, sdk.ErrUnknownAddress(addr.String())
|
return 0, sdk.ErrUnknownAddress(addr.String())
|
||||||
|
@ -126,7 +126,7 @@ func (am AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (int64
|
||||||
return acc.GetSequence(), nil
|
return acc.GetSequence(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am AccountKeeper) setSequence(ctx sdk.Context, addr sdk.AccAddress, newSequence int64) sdk.Error {
|
func (am AccountKeeper) setSequence(ctx sdk.Context, addr sdk.AccAddress, newSequence uint64) sdk.Error {
|
||||||
acc := am.GetAccount(ctx, addr)
|
acc := am.GetAccount(ctx, addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return sdk.ErrUnknownAddress(addr.String())
|
return sdk.ErrUnknownAddress(addr.String())
|
||||||
|
@ -141,8 +141,8 @@ func (am AccountKeeper) setSequence(ctx sdk.Context, addr sdk.AccAddress, newSeq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns and increments the global account number counter
|
// Returns and increments the global account number counter
|
||||||
func (am AccountKeeper) GetNextAccountNumber(ctx sdk.Context) int64 {
|
func (am AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 {
|
||||||
var accNumber int64
|
var accNumber uint64
|
||||||
store := ctx.KVStore(am.key)
|
store := ctx.KVStore(am.key)
|
||||||
bz := store.Get(globalAccountNumberKey)
|
bz := store.Get(globalAccountNumberKey)
|
||||||
if bz == nil {
|
if bz == nil {
|
||||||
|
|
|
@ -49,7 +49,7 @@ func TestAccountMapperGetSet(t *testing.T) {
|
||||||
require.Nil(t, mapper.GetAccount(ctx, addr))
|
require.Nil(t, mapper.GetAccount(ctx, addr))
|
||||||
|
|
||||||
// set some values on the account and save it
|
// set some values on the account and save it
|
||||||
newSequence := int64(20)
|
newSequence := uint64(20)
|
||||||
acc.SetSequence(newSequence)
|
acc.SetSequence(newSequence)
|
||||||
mapper.SetAccount(ctx, acc)
|
mapper.SetAccount(ctx, acc)
|
||||||
|
|
||||||
|
@ -75,8 +75,8 @@ func TestAccountMapperRemoveAccount(t *testing.T) {
|
||||||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||||
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||||
|
|
||||||
accSeq1 := int64(20)
|
accSeq1 := uint64(20)
|
||||||
accSeq2 := int64(40)
|
accSeq2 := uint64(40)
|
||||||
|
|
||||||
acc1.SetSequence(accSeq1)
|
acc1.SetSequence(accSeq1)
|
||||||
acc2.SetSequence(accSeq2)
|
acc2.SetSequence(accSeq2)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue