Merge develop
This commit is contained in:
commit
60fc7c7919
|
@ -162,6 +162,24 @@ jobs:
|
|||
export PATH="$GOBIN:$PATH"
|
||||
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:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
|
@ -301,6 +319,9 @@ workflows:
|
|||
- test_sim_gaia_import_export:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim_gaia_simulation_after_import:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
- test_sim_gaia_multi_seed:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
|
|
|
@ -643,6 +643,7 @@
|
|||
"github.com/bgentry/speakeasy",
|
||||
"github.com/btcsuite/btcd/btcec",
|
||||
"github.com/cosmos/go-bip39",
|
||||
"github.com/gogo/protobuf/proto",
|
||||
"github.com/golang/protobuf/proto",
|
||||
"github.com/gorilla/mux",
|
||||
"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..."
|
||||
@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:
|
||||
@echo "Running multi-seed Gaia simulation. This may take awhile!"
|
||||
@bash scripts/multisim.sh 25
|
||||
|
|
23
PENDING.md
23
PENDING.md
|
@ -11,13 +11,18 @@ BREAKING CHANGES
|
|||
* [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] [\#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
|
||||
* [mint] [\#2825] minting now occurs every block, inflation parameter updates still hourly
|
||||
|
||||
* SDK
|
||||
* [\#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.
|
||||
* [\#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
|
||||
|
||||
|
@ -32,6 +37,7 @@ FEATURES
|
|||
* [gov][cli] [\#2479](https://github.com/cosmos/cosmos-sdk/issues/2479) Added governance
|
||||
parameter query commands.
|
||||
* [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
|
||||
* [app] \#2791 Support export at a specific height, with `gaiad export --height=HEIGHT`.
|
||||
|
@ -39,9 +45,11 @@ FEATURES
|
|||
for getting governance parameters.
|
||||
* [app] \#2663 - Runtime-assertable invariants
|
||||
* [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
|
||||
* [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
|
||||
|
||||
|
@ -50,16 +58,27 @@ IMPROVEMENTS
|
|||
|
||||
* 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
|
||||
* [\#2836](https://github.com/cosmos/cosmos-sdk/pull/2836) Expose LCD router to allow users to register routes there.
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [\#2749](https://github.com/cosmos/cosmos-sdk/pull/2749) Add --chain-id flag to gaiad testnet
|
||||
|
||||
* Gaia
|
||||
- #2772 Update BaseApp to not persist state when the ante handler fails on DeliverTx.
|
||||
- #2773 Require moniker to be provided on `gaiad init`.
|
||||
- #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
|
||||
- [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
|
||||
- #2796 Update to go-amino 0.14.1
|
||||
|
@ -68,16 +87,20 @@ IMPROVEMENTS
|
|||
BUG FIXES
|
||||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
- [gaia-lite] #2868 Added handler for governance tally endpoit
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
|
||||
* Gaia
|
||||
* [\#2723] Use `cosmosvalcons` Bech32 prefix in `tendermint show-address`
|
||||
* [\#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
|
||||
|
||||
- \#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
|
||||
* [\#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"
|
||||
"strings"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
|
@ -20,11 +20,8 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/version"
|
||||
)
|
||||
|
||||
// Key to store the header in the DB itself.
|
||||
// Use the db directly instead of a store to avoid
|
||||
// conflicts with handlers writing to the store
|
||||
// and to avoid affecting the Merkle root.
|
||||
var dbHeaderKey = []byte("header")
|
||||
// Key to store the consensus params in the main store.
|
||||
var mainConsensusParamsKey = []byte("consensus_params")
|
||||
|
||||
// Enum mode for app.runTx
|
||||
type runTxMode uint8
|
||||
|
@ -47,12 +44,13 @@ type BaseApp struct {
|
|||
cms sdk.CommitMultiStore // Main (uncached) state
|
||||
router Router // handle any kind of message
|
||||
queryRouter QueryRouter // router for redirecting query calls
|
||||
codespacer *sdk.Codespacer // handle module codespacing
|
||||
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
|
||||
anteHandler sdk.AnteHandler // ante handler for fee and auth
|
||||
initChainer sdk.InitChainer // initialize state with validators and state blob
|
||||
beginBlocker sdk.BeginBlocker // logic to run before any txs
|
||||
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
|
||||
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
|
||||
|
||||
// flag for sealing
|
||||
|
@ -79,10 +81,6 @@ var _ abci.Application = (*BaseApp)(nil)
|
|||
|
||||
// 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.
|
||||
// Accepts a user-defined txDecoder
|
||||
// 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),
|
||||
router: NewRouter(),
|
||||
queryRouter: NewQueryRouter(),
|
||||
codespacer: sdk.NewCodespacer(),
|
||||
txDecoder: txDecoder,
|
||||
}
|
||||
|
||||
// Register the undefined & root codespaces, which should not be used by
|
||||
// any modules.
|
||||
app.codespacer.RegisterOrPanic(sdk.CodespaceRoot)
|
||||
for _, option := range options {
|
||||
option(app)
|
||||
}
|
||||
|
@ -118,11 +111,6 @@ func (app *BaseApp) SetCommitMultiStoreTracer(w io.Writer) {
|
|||
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
|
||||
func (app *BaseApp) MountStoresIAVL(keys ...*sdk.KVStoreKey) {
|
||||
for _, key := range keys {
|
||||
|
@ -148,21 +136,23 @@ func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) {
|
|||
}
|
||||
|
||||
// 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()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return app.initFromStore(mainKey)
|
||||
return app.initFromMainStore(mainKey)
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return app.initFromStore(mainKey)
|
||||
return app.initFromMainStore(mainKey)
|
||||
}
|
||||
|
||||
// the last CommitID of the multistore
|
||||
|
@ -176,13 +166,34 @@ func (app *BaseApp) LastBlockHeight() int64 {
|
|||
}
|
||||
|
||||
// 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.
|
||||
// TODO: we don't actually need the main store here
|
||||
main := app.cms.GetKVStore(mainKey)
|
||||
if main == nil {
|
||||
mainStore := app.cms.GetKVStore(mainKey)
|
||||
if mainStore == nil {
|
||||
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
|
||||
app.setCheckState(abci.Header{})
|
||||
|
||||
|
@ -211,6 +222,10 @@ func (st *state) CacheMultiStore() sdk.CacheMultiStore {
|
|||
return st.ms.CacheMultiStore()
|
||||
}
|
||||
|
||||
func (st *state) Context() sdk.Context {
|
||||
return st.ctx
|
||||
}
|
||||
|
||||
func (app *BaseApp) setCheckState(header abci.Header) {
|
||||
ms := app.cms.CacheMultiStore()
|
||||
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
|
||||
|
@ -249,8 +287,15 @@ func (app *BaseApp) SetOption(req abci.RequestSetOption) (res abci.ResponseSetOp
|
|||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
// 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
|
||||
app.setDeliverState(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 {
|
||||
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)
|
||||
|
||||
// NOTE: we don't commit, but BeginBlock for block 1
|
||||
|
@ -329,7 +379,8 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc
|
|||
}
|
||||
case "version":
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(sdk.ABCICodeOK),
|
||||
Code: uint32(sdk.CodeOK),
|
||||
Codespace: string(sdk.CodespaceRoot),
|
||||
Value: []byte(version.GetVersion()),
|
||||
}
|
||||
default:
|
||||
|
@ -339,7 +390,8 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc
|
|||
// Encode with json
|
||||
value := codec.Cdc.MustMarshalBinaryLengthPrefixed(result)
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(sdk.ABCICodeOK),
|
||||
Code: uint32(sdk.CodeOK),
|
||||
Codespace: string(sdk.CodespaceRoot),
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
// Cache wrap the commit-multistore for safety.
|
||||
ctx := sdk.NewContext(app.cms.CacheMultiStore(), app.checkState.ctx.BlockHeader(), true, app.Logger).
|
||||
WithMinimumFees(app.minimumFees)
|
||||
|
||||
|
@ -400,12 +453,13 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
|
|||
resBytes, err := querier(ctx, path[2:], req)
|
||||
if err != nil {
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(err.ABCICode()),
|
||||
Code: uint32(err.Code()),
|
||||
Codespace: string(err.Codespace()),
|
||||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(sdk.ABCICodeOK),
|
||||
Code: uint32(sdk.CodeOK),
|
||||
Value: resBytes,
|
||||
}
|
||||
}
|
||||
|
@ -427,9 +481,20 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
|||
} else {
|
||||
// In the first block, app.deliverState.ctx will already be initialized
|
||||
// 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 {
|
||||
res = app.beginBlocker(app.deliverState.ctx, req)
|
||||
}
|
||||
|
@ -459,17 +524,18 @@ func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) {
|
|||
Code: uint32(result.Code),
|
||||
Data: result.Data,
|
||||
Log: result.Log,
|
||||
GasWanted: result.GasWanted,
|
||||
GasUsed: result.GasUsed,
|
||||
GasWanted: int64(result.GasWanted), // TODO: Should type accept unsigned ints?
|
||||
GasUsed: int64(result.GasUsed), // TODO: Should type accept unsigned ints?
|
||||
Tags: result.Tags,
|
||||
}
|
||||
}
|
||||
|
||||
// Implements ABCI
|
||||
func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
|
||||
|
||||
// Decode the Tx.
|
||||
var result sdk.Result
|
||||
var tx, err = app.txDecoder(txBytes)
|
||||
var result sdk.Result
|
||||
if err != nil {
|
||||
result = err.Result()
|
||||
} else {
|
||||
|
@ -482,10 +548,11 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
|
|||
// Tell the blockchain engine (i.e. Tendermint).
|
||||
return abci.ResponseDeliverTx{
|
||||
Code: uint32(result.Code),
|
||||
Codespace: string(result.Codespace),
|
||||
Data: result.Data,
|
||||
Log: result.Log,
|
||||
GasWanted: result.GasWanted,
|
||||
GasUsed: result.GasUsed,
|
||||
GasWanted: int64(result.GasWanted), // TODO: Should type accept unsigned ints?
|
||||
GasUsed: int64(result.GasUsed), // TODO: Should type accept unsigned ints?
|
||||
Tags: result.Tags,
|
||||
}
|
||||
}
|
||||
|
@ -501,7 +568,6 @@ func validateBasicTxMsgs(msgs []sdk.Msg) sdk.Error {
|
|||
// Validate the Msg.
|
||||
err := msg.ValidateBasic()
|
||||
if err != nil {
|
||||
err = err.WithDefaultCodespace(sdk.CodespaceRoot)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -509,13 +575,13 @@ func validateBasicTxMsgs(msgs []sdk.Msg) sdk.Error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// retrieve the context for the ante handler and store the tx bytes; store
|
||||
// the vote infos if the tx runs within the deliverTx() state.
|
||||
func (app *BaseApp) getContextForAnte(mode runTxMode, txBytes []byte) (ctx sdk.Context) {
|
||||
// Get the context
|
||||
ctx = getState(app, mode).ctx.WithTxBytes(txBytes)
|
||||
if mode == runTxModeDeliver {
|
||||
ctx = ctx.WithVoteInfos(app.voteInfos)
|
||||
// retrieve the context for the tx w/ txBytes and other memoized values.
|
||||
func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) (ctx sdk.Context) {
|
||||
ctx = app.getState(mode).ctx.
|
||||
WithTxBytes(txBytes).
|
||||
WithVoteInfos(app.voteInfos)
|
||||
if mode == runTxModeSimulate {
|
||||
ctx, _ = ctx.CacheContext()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -526,7 +592,8 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
|||
logs := make([]string, 0, len(msgs))
|
||||
var data []byte // NOTE: we 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 {
|
||||
// Match route.
|
||||
msgRoute := msg.Route()
|
||||
|
@ -553,6 +620,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
|||
if !msgResult.IsOK() {
|
||||
logs = append(logs, fmt.Sprintf("Msg %d failed: %s", msgIdx, msgResult.Log))
|
||||
code = msgResult.Code
|
||||
codespace = msgResult.Codespace
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -563,6 +631,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
|
|||
// Set the final gas values.
|
||||
result = sdk.Result{
|
||||
Code: code,
|
||||
Codespace: codespace,
|
||||
Data: data,
|
||||
Log: strings.Join(logs, "\n"),
|
||||
GasUsed: ctx.GasMeter().GasConsumed(),
|
||||
|
@ -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,
|
||||
// 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 {
|
||||
return app.checkState
|
||||
}
|
||||
|
@ -583,24 +652,45 @@ func getState(app *BaseApp, mode runTxMode) *state {
|
|||
return app.deliverState
|
||||
}
|
||||
|
||||
func (app *BaseApp) initializeContext(ctx sdk.Context, mode runTxMode) sdk.Context {
|
||||
if mode == runTxModeSimulate {
|
||||
ctx = ctx.WithMultiStore(getState(app, runTxModeSimulate).CacheMultiStore())
|
||||
// cacheTxContext returns a new context based off of the provided context with
|
||||
// a cache wrapped multi-store.
|
||||
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
|
||||
// anteHandler. txBytes may be nil in some cases, eg. in tests. Also, in the
|
||||
// future we may support "internal" transactions.
|
||||
// anteHandler. The provided txBytes may be nil in some cases, eg. in tests. For
|
||||
// further details on transaction execution, reference the BaseApp SDK
|
||||
// documentation.
|
||||
func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk.Result) {
|
||||
// NOTE: GasWanted should be returned by the AnteHandler. GasUsed is
|
||||
// determined by the GasMeter. We need access to the context to get the gas
|
||||
// meter so we initialize upfront.
|
||||
var gasWanted int64
|
||||
var msCache sdk.CacheMultiStore
|
||||
ctx := app.getContextForAnte(mode, txBytes)
|
||||
ctx = app.initializeContext(ctx, mode)
|
||||
var gasWanted uint64
|
||||
|
||||
ctx := app.getContextForTx(mode, txBytes)
|
||||
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() {
|
||||
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()
|
||||
}()
|
||||
|
||||
// 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()
|
||||
if err := validateBasicTxMsgs(msgs); err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
// run the ante handler
|
||||
// Execute the ante handler if one is defined.
|
||||
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 {
|
||||
return result
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
if mode == runTxModeSimulate {
|
||||
result = app.runMsgs(ctx, msgs, mode)
|
||||
result.GasWanted = gasWanted
|
||||
if mode == runTxModeCheck {
|
||||
return
|
||||
}
|
||||
|
||||
// Keep the state in a transient CacheWrap in case processing the messages
|
||||
// fails.
|
||||
msCache = getState(app, mode).CacheMultiStore()
|
||||
if msCache.TracingEnabled() {
|
||||
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)
|
||||
// Create a new context based off of the existing context with a cache wrapped
|
||||
// multi-store in case message processing fails.
|
||||
runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes)
|
||||
result = app.runMsgs(runMsgCtx, msgs, mode)
|
||||
result.GasWanted = gasWanted
|
||||
|
||||
if mode == runTxModeSimulate {
|
||||
return
|
||||
}
|
||||
|
||||
// only update state if all messages pass
|
||||
if result.IsOK() {
|
||||
msCache.Write()
|
||||
|
@ -679,14 +791,6 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc
|
|||
// Implements ABCI
|
||||
func (app *BaseApp) Commit() (res abci.ResponseCommit) {
|
||||
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
|
||||
app.deliverState.ms.Write()
|
||||
|
|
|
@ -56,7 +56,9 @@ func setupBaseApp(t *testing.T, options ...func(*BaseApp)) *BaseApp {
|
|||
require.Equal(t, t.Name(), app.Name())
|
||||
|
||||
// no stores are mounted
|
||||
require.Panics(t, func() { app.LoadLatestVersion(capKey1) })
|
||||
require.Panics(t, func() {
|
||||
app.LoadLatestVersion(capKey1)
|
||||
})
|
||||
|
||||
app.MountStoresIAVL(capKey1, capKey2)
|
||||
|
||||
|
@ -284,10 +286,22 @@ func TestInitChainer(t *testing.T) {
|
|||
type txTest struct {
|
||||
Msgs []sdk.Msg
|
||||
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
|
||||
func (tx txTest) GetMsgs() []sdk.Msg { return tx.Msgs }
|
||||
func (tx txTest) ValidateBasic() sdk.Error { return nil }
|
||||
|
||||
const (
|
||||
routeMsgCounter = "msgCounter"
|
||||
|
@ -298,6 +312,7 @@ const (
|
|||
// Otherwise it's up to the handlers
|
||||
type msgCounter struct {
|
||||
Counter int64
|
||||
FailOnHandler bool
|
||||
}
|
||||
|
||||
// Implements Msg
|
||||
|
@ -315,9 +330,9 @@ func (msg msgCounter) ValidateBasic() sdk.Error {
|
|||
func newTxCounter(txInt int64, msgInts ...int64) *txTest {
|
||||
var msgs []sdk.Msg
|
||||
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
|
||||
|
@ -369,8 +384,13 @@ func testTxDecoder(cdc *codec.Codec) sdk.TxDecoder {
|
|||
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) {
|
||||
store := ctx.KVStore(capKey)
|
||||
msgCounter := tx.(txTest).Counter
|
||||
res = incrementingCounter(t, store, storeKey, msgCounter)
|
||||
txTest := tx.(txTest)
|
||||
|
||||
if txTest.FailOnAnte {
|
||||
return newCtx, sdk.ErrInternal("ante handler failure").Result(), true
|
||||
}
|
||||
|
||||
res = incrementingCounter(t, store, storeKey, txTest.Counter)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -381,10 +401,15 @@ func handlerMsgCounter(t *testing.T, capKey *sdk.KVStoreKey, deliverKey []byte)
|
|||
var msgCount int64
|
||||
switch m := msg.(type) {
|
||||
case *msgCounter:
|
||||
if m.FailOnHandler {
|
||||
return sdk.ErrInternal("message handler failure").Result()
|
||||
}
|
||||
|
||||
msgCount = m.Counter
|
||||
case *msgCounter2:
|
||||
msgCount = m.Counter
|
||||
}
|
||||
|
||||
return incrementingCounter(t, store, deliverKey, msgCount)
|
||||
}
|
||||
}
|
||||
|
@ -491,6 +516,7 @@ func TestDeliverTx(t *testing.T) {
|
|||
}
|
||||
|
||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||
app.InitChain(abci.RequestInitChain{})
|
||||
|
||||
// Create same codec used in txDecoder
|
||||
codec := codec.New()
|
||||
|
@ -596,7 +622,7 @@ func TestConcurrentCheckDeliver(t *testing.T) {
|
|||
// Simulate() and Query("/app/simulate", txBytes) should give
|
||||
// the same results.
|
||||
func TestSimulateTx(t *testing.T) {
|
||||
gasConsumed := int64(5)
|
||||
gasConsumed := uint64(5)
|
||||
|
||||
anteOpt := func(bapp *BaseApp) {
|
||||
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{}
|
||||
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
|
||||
|
@ -701,7 +728,8 @@ func TestRunInvalidTransaction(t *testing.T) {
|
|||
tx := testCase.tx
|
||||
res := app.Deliver(tx)
|
||||
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 {
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
}
|
||||
|
@ -710,13 +738,15 @@ func TestRunInvalidTransaction(t *testing.T) {
|
|||
|
||||
// Transaction with no known route
|
||||
{
|
||||
unknownRouteTx := txTest{[]sdk.Msg{msgNoRoute{}}, 0}
|
||||
unknownRouteTx := txTest{[]sdk.Msg{msgNoRoute{}}, 0, false}
|
||||
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)
|
||||
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
|
||||
|
@ -732,13 +762,14 @@ func TestRunInvalidTransaction(t *testing.T) {
|
|||
txBytes, err := newCdc.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
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
|
||||
func TestTxGasLimits(t *testing.T) {
|
||||
gasGranted := int64(10)
|
||||
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))
|
||||
|
@ -763,7 +794,7 @@ func TestTxGasLimits(t *testing.T) {
|
|||
}()
|
||||
|
||||
count := tx.(*txTest).Counter
|
||||
newCtx.GasMeter().ConsumeGas(count, "counter-ante")
|
||||
newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante")
|
||||
res = sdk.Result{
|
||||
GasWanted: gasGranted,
|
||||
}
|
||||
|
@ -775,7 +806,7 @@ func TestTxGasLimits(t *testing.T) {
|
|||
routerOpt := func(bapp *BaseApp) {
|
||||
bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
count := msg.(msgCounter).Counter
|
||||
ctx.GasMeter().ConsumeGas(count, "counter-handler")
|
||||
ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler")
|
||||
return sdk.Result{}
|
||||
})
|
||||
}
|
||||
|
@ -786,7 +817,7 @@ func TestTxGasLimits(t *testing.T) {
|
|||
|
||||
testCases := []struct {
|
||||
tx *txTest
|
||||
gasUsed int64
|
||||
gasUsed uint64
|
||||
fail bool
|
||||
}{
|
||||
{newTxCounter(0, 0), 0, false},
|
||||
|
@ -819,7 +850,181 @@ func TestTxGasLimits(t *testing.T) {
|
|||
if !tc.fail {
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%d: %v, %v", i, tc, res))
|
||||
} 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
|
||||
}
|
||||
|
||||
// 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
|
||||
// decoder.
|
||||
func (ctx CLIContext) WithAccountDecoder(decoder auth.AccountDecoder) CLIContext {
|
||||
ctx.AccDecoder = decoder
|
||||
func (ctx CLIContext) WithAccountDecoder(cdc *codec.Codec) CLIContext {
|
||||
ctx.AccDecoder = GetAccountDecoder(cdc)
|
||||
return ctx
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ func (ctx CLIContext) GetFromName() (string, error) {
|
|||
|
||||
// GetAccountNumber returns the next account number for the given account
|
||||
// address.
|
||||
func (ctx CLIContext) GetAccountNumber(address []byte) (int64, error) {
|
||||
func (ctx CLIContext) GetAccountNumber(address []byte) (uint64, error) {
|
||||
account, err := ctx.GetAccount(address)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -103,7 +103,7 @@ func (ctx CLIContext) GetAccountNumber(address []byte) (int64, error) {
|
|||
|
||||
// GetAccountSequence returns the sequence number for the given account
|
||||
// address.
|
||||
func (ctx CLIContext) GetAccountSequence(address []byte) (int64, error) {
|
||||
func (ctx CLIContext) GetAccountSequence(address []byte) (uint64, error) {
|
||||
account, err := ctx.GetAccount(address)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
@ -36,6 +36,13 @@ const (
|
|||
FlagDryRun = "dry-run"
|
||||
FlagGenerateOnly = "generate-only"
|
||||
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
|
||||
|
@ -67,8 +74,8 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
|||
for _, c := range cmds {
|
||||
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().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
|
||||
c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx")
|
||||
c.Flags().Uint64(FlagAccountNumber, 0, "AccountNumber 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(FlagFee, "", "Fee to pay along with transaction")
|
||||
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
|
||||
|
@ -92,12 +99,32 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
|||
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
|
||||
|
||||
// GasSetting encapsulates the possible values passed through the --gas flag.
|
||||
type GasSetting struct {
|
||||
Simulate bool
|
||||
Gas int64
|
||||
Gas uint64
|
||||
}
|
||||
|
||||
// Type returns the flag's value type.
|
||||
|
@ -113,18 +140,18 @@ func (v *GasSetting) String() string {
|
|||
if v.Simulate {
|
||||
return GasFlagSimulate
|
||||
}
|
||||
return strconv.FormatInt(v.Gas, 10)
|
||||
return strconv.FormatUint(v.Gas, 10)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
case "":
|
||||
gas = DefaultGasLimit
|
||||
case GasFlagSimulate:
|
||||
simulate = true
|
||||
default:
|
||||
gas, err = strconv.ParseInt(s, 10, 64)
|
||||
gas, err = strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("gas must be either integer or %q", GasFlagSimulate)
|
||||
return
|
||||
|
|
|
@ -2,20 +2,17 @@ package keys
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||
"net/http"
|
||||
"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"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
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
|
||||
|
|
|
@ -284,7 +284,7 @@ func TestCoinSend(t *testing.T) {
|
|||
|
||||
// test failure with negative gas
|
||||
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
|
||||
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.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
|
||||
require.Equal(t, gasEstimate, resultTx.DeliverTx.GasWanted)
|
||||
require.Equal(t, gasEstimate, resultTx.DeliverTx.GasUsed)
|
||||
require.Equal(t, gasEstimate, uint64(resultTx.DeliverTx.GasWanted))
|
||||
require.Equal(t, gasEstimate, uint64(resultTx.DeliverTx.GasUsed))
|
||||
}
|
||||
|
||||
func TestTxs(t *testing.T) {
|
||||
|
@ -696,7 +696,7 @@ func TestDeposit(t *testing.T) {
|
|||
func TestVote(t *testing.T) {
|
||||
name, password := "test", "1234567890"
|
||||
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()
|
||||
|
||||
// create SubmitProposal TX
|
||||
|
@ -714,7 +714,7 @@ func TestVote(t *testing.T) {
|
|||
proposal := getProposal(t, port, proposalID)
|
||||
require.Equal(t, "Test", proposal.GetTitle())
|
||||
|
||||
// create SubmitProposal TX
|
||||
// deposit
|
||||
resultTx = doDeposit(t, port, seed, name, password, addr, proposalID, 5)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
|
@ -722,7 +722,7 @@ func TestVote(t *testing.T) {
|
|||
proposal = getProposal(t, port, proposalID)
|
||||
require.Equal(t, gov.StatusVotingPeriod, proposal.GetStatus())
|
||||
|
||||
// create SubmitProposal TX
|
||||
// vote
|
||||
resultTx = doVote(t, port, seed, name, password, addr, proposalID)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
|
@ -734,6 +734,20 @@ func TestVote(t *testing.T) {
|
|||
vote := getVote(t, port, proposalID, addr)
|
||||
require.Equal(t, proposalID, vote.ProposalID)
|
||||
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) {
|
||||
|
@ -853,11 +867,11 @@ func TestProposalsQuery(t *testing.T) {
|
|||
require.Equal(t, proposalID3, (proposals[2]).GetProposalID())
|
||||
|
||||
// Test query deposited by addr1
|
||||
proposals = getProposalsFilterDepositer(t, port, addrs[0])
|
||||
proposals = getProposalsFilterDepositor(t, port, addrs[0])
|
||||
require.Equal(t, proposalID1, (proposals[0]).GetProposalID())
|
||||
|
||||
// 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, proposalID3, (proposals[1]).GetProposalID())
|
||||
|
||||
|
@ -871,7 +885,7 @@ func TestProposalsQuery(t *testing.T) {
|
|||
require.Equal(t, proposalID3, (proposals[0]).GetProposalID())
|
||||
|
||||
// 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())
|
||||
|
||||
// Test query votes on Proposal 2
|
||||
|
@ -1381,8 +1395,8 @@ func getDeposits(t *testing.T, port string, proposalID uint64) []gov.Deposit {
|
|||
return deposits
|
||||
}
|
||||
|
||||
func getDeposit(t *testing.T, port string, proposalID uint64, depositerAddr sdk.AccAddress) gov.Deposit {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil)
|
||||
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, depositorAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var deposit gov.Deposit
|
||||
err := cdc.UnmarshalJSON([]byte(body), &deposit)
|
||||
|
@ -1408,6 +1422,15 @@ func getVotes(t *testing.T, port string, proposalID uint64) []gov.Vote {
|
|||
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 {
|
||||
res, body := Request(t, port, "GET", "/gov/proposals", nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
@ -1418,8 +1441,8 @@ func getProposalsAll(t *testing.T, port string) []gov.Proposal {
|
|||
return proposals
|
||||
}
|
||||
|
||||
func getProposalsFilterDepositer(t *testing.T, port string, depositerAddr sdk.AccAddress) []gov.Proposal {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositer=%s", depositerAddr), nil)
|
||||
func getProposalsFilterDepositor(t *testing.T, port string, depositorAddr sdk.AccAddress) []gov.Proposal {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositor=%s", depositorAddr), nil)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
var proposals []gov.Proposal
|
||||
|
@ -1438,8 +1461,8 @@ func getProposalsFilterVoter(t *testing.T, port string, voterAddr sdk.AccAddress
|
|||
return proposals
|
||||
}
|
||||
|
||||
func getProposalsFilterVoterDepositer(t *testing.T, port string, voterAddr, depositerAddr sdk.AccAddress) []gov.Proposal {
|
||||
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals?depositer=%s&voter=%s", depositerAddr, voterAddr), nil)
|
||||
func getProposalsFilterVoterDepositor(t *testing.T, port string, voterAddr, depositorAddr sdk.AccAddress) []gov.Proposal {
|
||||
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)
|
||||
|
||||
var proposals []gov.Proposal
|
||||
|
@ -1501,7 +1524,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
|
|||
|
||||
// deposit on proposal
|
||||
jsonStr := []byte(fmt.Sprintf(`{
|
||||
"depositer": "%s",
|
||||
"depositor": "%s",
|
||||
"amount": [{ "denom": "%s", "amount": "%d" }],
|
||||
"base_req": {
|
||||
"name": "%s",
|
||||
|
|
|
@ -10,65 +10,79 @@ import (
|
|||
"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/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
keybase "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"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/rakyll/statik/fs"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
|
||||
// Import statik for light client stuff
|
||||
_ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
|
||||
)
|
||||
|
||||
const (
|
||||
flagListenAddr = "laddr"
|
||||
flagCORS = "cors"
|
||||
flagMaxOpenConnections = "max-open"
|
||||
flagInsecure = "insecure"
|
||||
flagSSLHosts = "ssl-hosts"
|
||||
flagSSLCertFile = "ssl-certfile"
|
||||
flagSSLKeyFile = "ssl-keyfile"
|
||||
)
|
||||
// RestServer represents the Light Client Rest server
|
||||
type RestServer struct {
|
||||
Mux *mux.Router
|
||||
CliCtx context.CLIContext
|
||||
KeyBase keybase.Keybase
|
||||
Cdc *codec.Codec
|
||||
|
||||
// ServeCommand will generate a long-running rest server
|
||||
// (aka Light Client Daemon) that exposes functionality similar
|
||||
// to the cli, but over rest
|
||||
func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
||||
log log.Logger
|
||||
listener net.Listener
|
||||
fingerprint string
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "rest-server",
|
||||
Short: "Start LCD (light-client daemon), a local REST server",
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
listenAddr := viper.GetString(flagListenAddr)
|
||||
handler := createHandler(cdc)
|
||||
// NewRestServer creates a new rest server instance
|
||||
func NewRestServer(cdc *codec.Codec) *RestServer {
|
||||
r := mux.NewRouter()
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
registerSwaggerUI(handler)
|
||||
// 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")
|
||||
maxOpen := viper.GetInt(flagMaxOpenConnections)
|
||||
sslHosts := viper.GetString(flagSSLHosts)
|
||||
certFile := viper.GetString(flagSSLCertFile)
|
||||
keyFile := viper.GetString(flagSSLKeyFile)
|
||||
|
||||
var listener net.Listener
|
||||
var fingerprint string
|
||||
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 := listener.Close()
|
||||
logger.Error("error closing listener", "err", err)
|
||||
err := rs.listener.Close()
|
||||
rs.log.Error("error closing listener", "err", err)
|
||||
})
|
||||
|
||||
var cleanupFunc func()
|
||||
|
||||
// TODO: re-enable insecure mode once #2715 has been addressed
|
||||
if viper.GetBool(flagInsecure) {
|
||||
if insecure {
|
||||
fmt.Println(
|
||||
"Insecure mode is temporarily disabled, please locally generate an " +
|
||||
"SSL certificate to test. Support will be re-enabled soon!",
|
||||
|
@ -89,97 +103,76 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
// cert/key pair is provided, read the fingerprint
|
||||
fingerprint, err = fingerprintFromFile(certFile)
|
||||
rs.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)
|
||||
certFile, keyFile, rs.fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cleanupFunc = func() {
|
||||
defer func() {
|
||||
os.Remove(certFile)
|
||||
os.Remove(keyFile)
|
||||
}()
|
||||
}
|
||||
|
||||
defer cleanupFunc()
|
||||
}
|
||||
|
||||
listener, err = tmserver.StartHTTPAndTLSServer(
|
||||
listenAddr, handler,
|
||||
rs.listener, err = tmserver.StartHTTPAndTLSServer(
|
||||
listenAddr, rs.Mux,
|
||||
certFile, keyFile,
|
||||
logger,
|
||||
rs.log,
|
||||
tmserver.Config{MaxOpenConnections: maxOpen},
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info(fingerprint)
|
||||
logger.Info("REST server started")
|
||||
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
|
||||
// (aka Light Client Daemon) that exposes functionality similar
|
||||
// to the cli, but over rest
|
||||
func (rs *RestServer) ServeCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "rest-server",
|
||||
Short: "Start LCD (light-client daemon), a local REST server",
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
rs.setKeybase(nil)
|
||||
// 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))
|
||||
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
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(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))
|
||||
client.RegisterRestServerFlags(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func createHandler(cdc *codec.Codec) *mux.Router {
|
||||
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) {
|
||||
func (rs *RestServer) registerSwaggerUI() {
|
||||
statikFS, err := fs.New()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
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 {
|
||||
|
|
|
@ -1226,8 +1226,8 @@ paths:
|
|||
required: false
|
||||
type: string
|
||||
- in: query
|
||||
name: depositer
|
||||
description: depositer address
|
||||
name: depositor
|
||||
description: depositor address
|
||||
required: false
|
||||
type: string
|
||||
- in: query
|
||||
|
@ -1281,7 +1281,7 @@ paths:
|
|||
properties:
|
||||
base_req:
|
||||
"$ref": "#/definitions/BaseReq"
|
||||
depositer:
|
||||
depositor:
|
||||
"$ref": "#/definitions/Address"
|
||||
amount:
|
||||
type: array
|
||||
|
@ -1321,6 +1321,29 @@ paths:
|
|||
description: Invalid proposal id
|
||||
500:
|
||||
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:
|
||||
post:
|
||||
summary: Vote a proposal
|
||||
|
@ -1418,10 +1441,10 @@ paths:
|
|||
description: Invalid proposal id
|
||||
500:
|
||||
description: Internal Server Error
|
||||
/gov/proposals/{proposalId}/deposits/{depositer}:
|
||||
/gov/proposals/{proposalId}/deposits/{depositor}:
|
||||
get:
|
||||
summary: Query deposit
|
||||
description: Query deposit by proposalId and depositer address
|
||||
description: Query deposit by proposalId and depositor address
|
||||
produces:
|
||||
- application/json
|
||||
tags:
|
||||
|
@ -1433,8 +1456,8 @@ paths:
|
|||
required: true
|
||||
in: path
|
||||
- type: string
|
||||
description: Bech32 depositer address
|
||||
name: depositer
|
||||
description: Bech32 depositor address
|
||||
name: depositor
|
||||
required: true
|
||||
in: path
|
||||
responses:
|
||||
|
@ -1443,7 +1466,7 @@ paths:
|
|||
schema:
|
||||
$ref: "#/definitions/Deposit"
|
||||
400:
|
||||
description: Invalid proposal id or depositer address
|
||||
description: Invalid proposal id or depositor address
|
||||
404:
|
||||
description: Found no deposit
|
||||
500:
|
||||
|
@ -1893,16 +1916,7 @@ definitions:
|
|||
proposal_status:
|
||||
type: string
|
||||
tally_result:
|
||||
type: object
|
||||
properties:
|
||||
yes:
|
||||
type: string
|
||||
abstain:
|
||||
type: string
|
||||
no:
|
||||
type: string
|
||||
no_with_veto:
|
||||
type: string
|
||||
$ref: "#/definitions/TallyResult"
|
||||
submit_time:
|
||||
type: string
|
||||
total_deposit:
|
||||
|
@ -1920,8 +1934,23 @@ definitions:
|
|||
"$ref": "#/definitions/Coin"
|
||||
proposal_id:
|
||||
type: integer
|
||||
depositer:
|
||||
depositor:
|
||||
"$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:
|
||||
type: object
|
||||
properties:
|
||||
|
|
|
@ -19,6 +19,8 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"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"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
@ -45,6 +47,12 @@ import (
|
|||
"github.com/tendermint/tendermint/proxy"
|
||||
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
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
|
||||
|
@ -103,6 +111,13 @@ func GetKeyBase(t *testing.T) crkeys.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.
|
||||
// It also requires that the key could be created.
|
||||
func CreateAddr(t *testing.T, name, password string, kb crkeys.Keybase) (sdk.AccAddress, string) {
|
||||
|
@ -288,7 +303,7 @@ func InitializeTestLCD(
|
|||
require.NoError(t, err)
|
||||
|
||||
tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress))
|
||||
lcd, err := startLCD(logger, listenAddr, cdc)
|
||||
lcd, err := startLCD(logger, listenAddr, cdc, t)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests.WaitForLCDStart(port)
|
||||
|
@ -347,8 +362,23 @@ func startTM(
|
|||
// startLCD starts the LCD.
|
||||
//
|
||||
// NOTE: This causes the thread to block.
|
||||
func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec) (net.Listener, error) {
|
||||
return tmrpc.StartHTTPServer(listenAddr, createHandler(cdc), logger, tmrpc.Config{})
|
||||
func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing.T) (net.Listener, error) {
|
||||
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
|
||||
|
|
|
@ -34,7 +34,7 @@ func WriteErrorResponse(w http.ResponseWriter, status int, err string) {
|
|||
|
||||
// WriteSimulationResponse prepares and writes an HTTP
|
||||
// response for transactions simulations.
|
||||
func WriteSimulationResponse(w http.ResponseWriter, gas int64) {
|
||||
func WriteSimulationResponse(w http.ResponseWriter, gas uint64) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas)))
|
||||
}
|
||||
|
@ -124,8 +124,8 @@ type BaseReq struct {
|
|||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
ChainID string `json:"chain_id"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
Sequence uint64 `json:"sequence"`
|
||||
Gas string `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package utils
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"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
|
||||
// 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
|
||||
// estimate gas and update TxBuilder accordingly
|
||||
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.
|
||||
// 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
|
||||
if offline {
|
||||
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)
|
||||
if err == nil {
|
||||
fmt.Printf("%s\n", json)
|
||||
fmt.Fprintf(w, "%s\n", json)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -152,7 +153,7 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
|||
|
||||
// nolint
|
||||
// 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)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -161,11 +162,11 @@ func simulateMsgs(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name stri
|
|||
return
|
||||
}
|
||||
|
||||
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
|
||||
return int64(adjustment * float64(estimate))
|
||||
func adjustGasEstimate(estimate uint64, adjustment float64) uint64 {
|
||||
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
|
||||
if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &simulationResult); err != nil {
|
||||
return 0, err
|
||||
|
|
|
@ -14,16 +14,16 @@ func TestParseQueryResponse(t *testing.T) {
|
|||
cdc := app.MakeCodec()
|
||||
sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: 10})
|
||||
gas, err := parseQueryResponse(cdc, sdkResBytes)
|
||||
assert.Equal(t, gas, int64(10))
|
||||
assert.Equal(t, gas, uint64(10))
|
||||
assert.Nil(t, err)
|
||||
gas, err = parseQueryResponse(cdc, []byte("fuzzy"))
|
||||
assert.Equal(t, gas, int64(0))
|
||||
assert.Equal(t, gas, uint64(0))
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestCalculateGas(t *testing.T) {
|
||||
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) {
|
||||
if wantErr {
|
||||
return nil, errors.New("")
|
||||
|
@ -32,15 +32,15 @@ func TestCalculateGas(t *testing.T) {
|
|||
}
|
||||
}
|
||||
type args struct {
|
||||
queryFuncGasUsed int64
|
||||
queryFuncGasUsed uint64
|
||||
queryFuncWantErr bool
|
||||
adjustment float64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantEstimate int64
|
||||
wantAdjusted int64
|
||||
wantEstimate uint64
|
||||
wantAdjusted uint64
|
||||
wantErr bool
|
||||
}{
|
||||
{"error", args{0, true, 1.2}, 0, 0, true},
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -22,7 +21,6 @@ import (
|
|||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -113,7 +111,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
app.cdc,
|
||||
app.keyStake, app.tkeyStake,
|
||||
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
|
||||
app.RegisterCodespace(stake.DefaultCodespace),
|
||||
stake.DefaultCodespace,
|
||||
)
|
||||
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
|
||||
app.paramsKeeper.Subspace(mint.DefaultParamspace),
|
||||
|
@ -124,19 +122,19 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
|||
app.keyDistr,
|
||||
app.paramsKeeper.Subspace(distr.DefaultParamspace),
|
||||
app.bankKeeper, &stakeKeeper, app.feeCollectionKeeper,
|
||||
app.RegisterCodespace(stake.DefaultCodespace),
|
||||
distr.DefaultCodespace,
|
||||
)
|
||||
app.slashingKeeper = slashing.NewKeeper(
|
||||
app.cdc,
|
||||
app.keySlashing,
|
||||
&stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
|
||||
app.RegisterCodespace(slashing.DefaultCodespace),
|
||||
slashing.DefaultCodespace,
|
||||
)
|
||||
app.govKeeper = gov.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyGov,
|
||||
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakeKeeper,
|
||||
app.RegisterCodespace(gov.DefaultCodespace),
|
||||
gov.DefaultCodespace,
|
||||
)
|
||||
|
||||
// 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
|
||||
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, "")
|
||||
}
|
||||
|
||||
// initialize store from a genesis state
|
||||
func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisState) []abci.ValidatorUpdate {
|
||||
// sort by account number to maintain consistency
|
||||
sort.Slice(genesisState.Accounts, func(i, j int) bool {
|
||||
return genesisState.Accounts[i].AccountNumber < genesisState.Accounts[j].AccountNumber
|
||||
|
@ -276,6 +264,22 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
|
||||
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
|
||||
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{
|
||||
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
|
||||
func (app *GaiaApp) LoadHeight(height int64) error {
|
||||
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
|
||||
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")
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
||||
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, stakeData stake.GenesisState, mintData mint.GenesisState,
|
||||
distrData distr.GenesisState, govData gov.GenesisState, slashingData slashing.GenesisState) GenesisState {
|
||||
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
|
||||
stakeData stake.GenesisState, mintData mint.GenesisState,
|
||||
distrData distr.GenesisState, govData gov.GenesisState,
|
||||
slashingData slashing.GenesisState) GenesisState {
|
||||
|
||||
return GenesisState{
|
||||
Accounts: accounts,
|
||||
|
@ -59,8 +61,8 @@ func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState, stak
|
|||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
Sequence int64 `json:"sequence_number"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence uint64 `json:"sequence_number"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
}
|
||||
|
||||
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
|
||||
// note that the pubkey input is this machines pubkey
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -280,10 +281,12 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm
|
|||
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
|
||||
accAuth := auth.NewBaseAccountWithAddress(addr)
|
||||
coins := sdk.Coins{
|
||||
{"fooToken", sdk.NewInt(1000)},
|
||||
{bondDenom, freeFermionsAcc},
|
||||
sdk.NewCoin("fooToken", sdk.NewInt(1000)),
|
||||
sdk.NewCoin(bondDenom, freeFermionsAcc),
|
||||
}
|
||||
|
||||
coins.Sort()
|
||||
|
||||
accAuth.Coins = coins
|
||||
return NewGenesisAccount(&accAuth)
|
||||
}
|
||||
|
|
|
@ -59,11 +59,13 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
if numInitiallyBonded > numAccs {
|
||||
numInitiallyBonded = numAccs
|
||||
}
|
||||
fmt.Printf("Selected randomly generated parameters for simulated genesis: {amount of steak per account: %v, initially bonded validators: %v}\n", amount, numInitiallyBonded)
|
||||
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
|
||||
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{
|
||||
Address: acc.Address,
|
||||
Coins: coins,
|
||||
|
@ -86,7 +88,8 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
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{
|
||||
Pool: stake.InitialPool(),
|
||||
Params: stake.Params{
|
||||
|
@ -95,7 +98,8 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
|||
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{
|
||||
Params: slashing.Params{
|
||||
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))),
|
||||
},
|
||||
}
|
||||
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{
|
||||
Minter: mint.Minter{
|
||||
InflationLastTime: time.Unix(0, 0),
|
||||
Inflation: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
||||
},
|
||||
Params: mint.Params{
|
||||
MintDenom: stakeTypes.DefaultBondDenom,
|
||||
InflationRateChange: sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
||||
InflationMax: sdk.NewDecWithPrec(20, 2),
|
||||
InflationMin: sdk.NewDecWithPrec(7, 2),
|
||||
GoalBonded: sdk.NewDecWithPrec(67, 2),
|
||||
},
|
||||
Minter: mint.InitialMinter(
|
||||
sdk.NewDecWithPrec(int64(r.Intn(99)), 2)),
|
||||
Params: mint.NewParams(
|
||||
stakeTypes.DefaultBondDenom,
|
||||
sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
|
||||
sdk.NewDecWithPrec(20, 2),
|
||||
sdk.NewDecWithPrec(7, 2),
|
||||
sdk.NewDecWithPrec(67, 2),
|
||||
uint64(60*60*8766/5)),
|
||||
}
|
||||
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 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.Tokens = 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)
|
||||
delegations = append(delegations, delegation)
|
||||
}
|
||||
|
@ -206,7 +210,7 @@ func BenchmarkFullGaiaSimulation(b *testing.B) {
|
|||
|
||||
// Run randomized simulation
|
||||
// TODO parameterize numbers, save for a later PR
|
||||
err := simulation.SimulateFromSeed(
|
||||
_, err := simulation.SimulateFromSeed(
|
||||
b, app.BaseApp, appStateFn, seed,
|
||||
testAndRunTxs(app),
|
||||
[]simulation.RandSetup{},
|
||||
|
@ -249,7 +253,7 @@ func TestFullGaiaSimulation(t *testing.T) {
|
|||
require.Equal(t, "GaiaApp", app.Name())
|
||||
|
||||
// Run randomized simulation
|
||||
err := simulation.SimulateFromSeed(
|
||||
_, err := simulation.SimulateFromSeed(
|
||||
t, app.BaseApp, appStateFn, seed,
|
||||
testAndRunTxs(app),
|
||||
[]simulation.RandSetup{},
|
||||
|
@ -291,7 +295,7 @@ func TestGaiaImportExport(t *testing.T) {
|
|||
require.Equal(t, "GaiaApp", app.Name())
|
||||
|
||||
// Run randomized simulation
|
||||
err := simulation.SimulateFromSeed(
|
||||
_, err := simulation.SimulateFromSeed(
|
||||
t, app.BaseApp, appStateFn, seed,
|
||||
testAndRunTxs(app),
|
||||
[]simulation.RandSetup{},
|
||||
|
@ -311,7 +315,7 @@ func TestGaiaImportExport(t *testing.T) {
|
|||
|
||||
fmt.Printf("Exporting genesis...\n")
|
||||
|
||||
appState, _, err := app.ExportAppStateAndValidators()
|
||||
appState, _, err := app.ExportAppStateAndValidators(false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -326,15 +330,16 @@ func TestGaiaImportExport(t *testing.T) {
|
|||
}()
|
||||
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil)
|
||||
require.Equal(t, "GaiaApp", newApp.Name())
|
||||
request := abci.RequestInitChain{
|
||||
AppStateBytes: appState,
|
||||
var genesisState GenesisState
|
||||
err = app.cdc.UnmarshalJSON(appState, &genesisState)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
newApp.InitChain(request)
|
||||
newApp.Commit()
|
||||
ctxB := newApp.NewContext(true, abci.Header{})
|
||||
newApp.initFromGenesisState(ctxB, genesisState)
|
||||
|
||||
fmt.Printf("Comparing stores...\n")
|
||||
ctxA := app.NewContext(true, abci.Header{})
|
||||
ctxB := newApp.NewContext(true, abci.Header{})
|
||||
type StoreKeysPrefixes struct {
|
||||
A sdk.StoreKey
|
||||
B sdk.StoreKey
|
||||
|
@ -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
|
||||
// and doesn't depend on gaia
|
||||
func TestAppStateDeterminism(t *testing.T) {
|
||||
|
|
|
@ -370,7 +370,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
require.Equal(t, " 1 - Test", proposalsQuery)
|
||||
|
||||
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))
|
||||
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())
|
||||
|
||||
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))
|
||||
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.Empty(t, stderr)
|
||||
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, 0, len(msg.GetSignatures()))
|
||||
|
||||
|
@ -491,7 +491,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
require.True(t, success)
|
||||
require.Empty(t, stderr)
|
||||
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, 0, len(msg.GetSignatures()))
|
||||
|
||||
|
@ -542,16 +542,19 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
|
|||
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||
"gaiacli tx broadcast %v --json %v", flags, signedTxFile.Name()))
|
||||
require.True(t, success)
|
||||
|
||||
var result struct {
|
||||
Response abci.ResponseDeliverTx
|
||||
}
|
||||
|
||||
require.Nil(t, app.MakeCodec().UnmarshalJSON([]byte(stdout), &result))
|
||||
require.Equal(t, msg.Fee.Gas, result.Response.GasUsed)
|
||||
require.Equal(t, msg.Fee.Gas, result.Response.GasWanted)
|
||||
require.Equal(t, msg.Fee.Gas, uint64(result.Response.GasUsed))
|
||||
require.Equal(t, msg.Fee.Gas, uint64(result.Response.GasWanted))
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
|
||||
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
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) {
|
||||
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 bar", gaiacliHome), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
||||
executeWriteCheckErr(t, fmt.Sprintf("gaiacli keys add --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
||||
executeWriteCheckErr(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
||||
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf(
|
||||
"gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||
chainID = executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome))
|
||||
|
@ -625,10 +629,10 @@ func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
|
|||
require.NoError(t, err)
|
||||
genDoc.AppState = appStateJSON
|
||||
genDoc.SaveAs(genFile)
|
||||
executeWrite(t, fmt.Sprintf(
|
||||
executeWriteCheckErr(t, fmt.Sprintf(
|
||||
"gaiad gentx --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome),
|
||||
app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiad collect-gentxs --home=%s", gaiadHome), app.DefaultKeyPass)
|
||||
executeWriteCheckErr(t, fmt.Sprintf("gaiad collect-gentxs --home=%s", gaiadHome), app.DefaultKeyPass)
|
||||
// get a free port, also setup some common flags
|
||||
servAddr, port, err = server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
|
@ -664,6 +668,10 @@ func readGenesisFile(t *testing.T, genFile string) types.GenesisDoc {
|
|||
//___________________________________________________________________________________
|
||||
// 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) {
|
||||
exitSuccess, _, _ = executeWriteRetStdStreams(t, cmdStr, writes...)
|
||||
return
|
||||
|
|
|
@ -1,22 +1,40 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/rakyll/statik/fs"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
|
@ -25,40 +43,56 @@ const (
|
|||
storeGov = "gov"
|
||||
storeSlashing = "slashing"
|
||||
storeStake = "stake"
|
||||
queryRouteStake = "stake"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "gaiacli",
|
||||
Short: "Command line interface for interacting with gaiad",
|
||||
}
|
||||
storeDist = "distr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Configure cobra to sort commands
|
||||
cobra.EnableCommandSorting = false
|
||||
|
||||
// Instantiate the codec for the command line application
|
||||
cdc := app.MakeCodec()
|
||||
|
||||
// Read in the configuration file for the sdk
|
||||
config := sdk.GetConfig()
|
||||
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
||||
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
|
||||
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
|
||||
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
|
||||
// the below functions and eliminate global vars, like we do
|
||||
// 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
|
||||
rootCmd.AddCommand(
|
||||
rpc.InitClientCommand(),
|
||||
rpc.StatusCommand(),
|
||||
client.ConfigCmd(),
|
||||
queryCmd(cdc),
|
||||
txCmd(cdc),
|
||||
queryCmd(cdc, mc),
|
||||
txCmd(cdc, mc),
|
||||
client.LineBreak,
|
||||
lcd.ServeCommand(cdc),
|
||||
rs.ServeCommand(),
|
||||
client.LineBreak,
|
||||
keys.Commands(),
|
||||
client.LineBreak,
|
||||
|
@ -74,9 +108,77 @@ func main() {
|
|||
|
||||
err = executor.Execute()
|
||||
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)
|
||||
}
|
||||
staticServer := http.FileServer(statikFS)
|
||||
rs.Mux.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer))
|
||||
}
|
||||
|
||||
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(
|
||||
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) {
|
||||
gApp := app.NewGaiaApp(logger, db, traceStore)
|
||||
if height != -1 {
|
||||
|
@ -71,5 +71,5 @@ func exportAppStateAndTMValidators(
|
|||
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
|
||||
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
|
||||
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.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), app.RegisterCodespace(slashing.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), slashing.DefaultCodespace)
|
||||
|
||||
// register message routes
|
||||
app.Router().
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestAddGenesisAccount(t *testing.T) {
|
|||
},
|
||||
false},
|
||||
{"dup account", args{
|
||||
app.GenesisState{Accounts: []app.GenesisAccount{app.GenesisAccount{Address:addr1}}},
|
||||
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
|
||||
addr1,
|
||||
sdk.Coins{}}, true},
|
||||
}
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"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/context"
|
||||
"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/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
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"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -66,7 +73,9 @@ following delegation and commission default parameters:
|
|||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -79,27 +88,40 @@ following delegation and commission default parameters:
|
|||
}
|
||||
// Run gaiad tx create-validator
|
||||
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey)
|
||||
createValidatorCmd := cli.GetCmdCreateValidator(cdc)
|
||||
|
||||
w, err := ioutil.TempFile("", "gentx")
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
cliCtx, txBldr, msg, err := cli.BuildCreateValidatorMsg(cliCtx, txBldr)
|
||||
if err != nil {
|
||||
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()
|
||||
signCmd := authcmd.GetSignCommand(cdc, authcmd.GetAccountDecoder(cdc))
|
||||
if w, err = prepareOutputFile(config.RootDir, nodeID); err != nil {
|
||||
// write the unsigned transaction to the buffer
|
||||
w := bytes.NewBuffer([]byte{})
|
||||
if err := utils.PrintUnsignedStdTx(w, txBldr, cliCtx, []sdk.Msg{msg}, true); err != nil {
|
||||
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() {
|
||||
viper.Set("offline", true)
|
||||
func makeOutputFilepath(rootDir, nodeID string) (string, error) {
|
||||
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) {
|
||||
writePath := filepath.Join(rootDir, "config", "gentx")
|
||||
if err = common.EnsureDir(writePath, 0700); err != nil {
|
||||
return
|
||||
func readUnsignedGenTxFile(cdc *codec.Codec, r io.Reader) (auth.StdTx, error) {
|
||||
var stdTx auth.StdTx
|
||||
bytes, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return stdTx, err
|
||||
}
|
||||
filename := filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID))
|
||||
return os.Create(filename)
|
||||
err = cdc.UnmarshalJSON(bytes, &stdTx)
|
||||
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"
|
||||
environment:
|
||||
- ID=0
|
||||
- LOG=$${LOG:-gaiad.log}
|
||||
- LOG=${LOG:-gaiad.log}
|
||||
volumes:
|
||||
- ./build:/gaiad:Z
|
||||
networks:
|
||||
|
@ -22,7 +22,7 @@ services:
|
|||
- "26659-26660:26656-26657"
|
||||
environment:
|
||||
- ID=1
|
||||
- LOG=$${LOG:-gaiad.log}
|
||||
- LOG=${LOG:-gaiad.log}
|
||||
volumes:
|
||||
- ./build:/gaiad:Z
|
||||
networks:
|
||||
|
@ -34,7 +34,7 @@ services:
|
|||
image: "tendermint/gaiadnode"
|
||||
environment:
|
||||
- ID=2
|
||||
- LOG=$${LOG:-gaiad.log}
|
||||
- LOG=${LOG:-gaiad.log}
|
||||
ports:
|
||||
- "26661-26662:26656-26657"
|
||||
volumes:
|
||||
|
@ -48,7 +48,7 @@ services:
|
|||
image: "tendermint/gaiadnode"
|
||||
environment:
|
||||
- ID=3
|
||||
- LOG=$${LOG:-gaiad.log}
|
||||
- LOG=${LOG:-gaiad.log}
|
||||
ports:
|
||||
- "26663-26664:26656-26657"
|
||||
volumes:
|
||||
|
|
|
@ -52,11 +52,11 @@ type Account interface {
|
|||
GetPubKey() crypto.PubKey // can return nil.
|
||||
SetPubKey(crypto.PubKey) error
|
||||
|
||||
GetAccountNumber() int64
|
||||
SetAccountNumber(int64) error
|
||||
GetAccountNumber() uint64
|
||||
SetAccountNumber(uint64) error
|
||||
|
||||
GetSequence() int64
|
||||
SetSequence(int64) error
|
||||
GetSequence() uint64
|
||||
SetSequence(uint64) error
|
||||
|
||||
GetCoins() sdk.Coins
|
||||
SetCoins(sdk.Coins) error
|
||||
|
@ -79,8 +79,8 @@ type BaseAccount struct {
|
|||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
PubKey crypto.PubKey `json:"public_key"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
Sequence uint64 `json:"sequence"`
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -161,8 +161,8 @@ The standard form for signatures is `StdSignature`:
|
|||
type StdSignature struct {
|
||||
crypto.PubKey `json:"pub_key"` // optional
|
||||
[]byte `json:"signature"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
Sequence uint64 `json:"sequence"`
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
const (
|
||||
app1Name = "App1"
|
||||
bankCodespace = "BANK"
|
||||
)
|
||||
|
||||
func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
|
||||
|
@ -107,7 +108,7 @@ func handleMsgSend(key *sdk.KVStoreKey) sdk.Handler {
|
|||
if !ok {
|
||||
// Create custom error message and return result
|
||||
// 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.
|
||||
|
@ -137,7 +138,7 @@ func handleFrom(store sdk.KVStore, from sdk.AccAddress, amt sdk.Coins) sdk.Resul
|
|||
accBytes := store.Get(from)
|
||||
if accBytes == nil {
|
||||
// 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.
|
||||
|
|
|
@ -126,7 +126,7 @@ func handleMsgIssue(keyIssue *sdk.KVStoreKey, keyAcc *sdk.KVStoreKey) sdk.Handle
|
|||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
issueMsg, ok := msg.(MsgIssue)
|
||||
if !ok {
|
||||
return sdk.NewError(2, 1, "MsgIssue is malformed").Result()
|
||||
return sdk.NewError(bankCodespace, 1, "MsgIssue is malformed").Result()
|
||||
}
|
||||
|
||||
// Retrieve stores
|
||||
|
|
|
@ -20,7 +20,7 @@ func TestEncoding(t *testing.T) {
|
|||
sendMsg := MsgSend{
|
||||
From: addr1,
|
||||
To: addr2,
|
||||
Amount: sdk.Coins{{"testCoins", sdk.NewInt(100)}},
|
||||
Amount: sdk.Coins{sdk.NewCoin("testCoins", sdk.NewInt(100))},
|
||||
}
|
||||
|
||||
// Construct transaction
|
||||
|
|
|
@ -30,7 +30,7 @@ func InitTestChain(bc *bapp.BaseApp, chainID string, addrs ...sdk.AccAddress) {
|
|||
for _, addr := range addrs {
|
||||
acc := GenesisAccount{
|
||||
Address: addr,
|
||||
Coins: sdk.Coins{{"testCoin", sdk.NewInt(100)}},
|
||||
Coins: sdk.Coins{sdk.NewCoin("testCoin", sdk.NewInt(100))},
|
||||
}
|
||||
accounts = append(accounts, &acc)
|
||||
}
|
||||
|
@ -61,12 +61,12 @@ func TestBadMsg(t *testing.T) {
|
|||
addr2 := priv2.PubKey().Address().Bytes()
|
||||
|
||||
// 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
|
||||
fee := auth.StdFee{
|
||||
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}, "")
|
||||
sig, err := priv1.Sign(signBytes)
|
||||
|
@ -108,11 +108,11 @@ func TestMsgSend(t *testing.T) {
|
|||
InitTestChain(bc, "test-chain", addr1)
|
||||
|
||||
// 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{
|
||||
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}, "")
|
||||
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.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace))
|
||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, ibc.DefaultCodespace)
|
||||
|
||||
// register message routes
|
||||
app.Router().
|
||||
|
|
|
@ -8,17 +8,28 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"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"
|
||||
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"
|
||||
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/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"
|
||||
stake "github.com/cosmos/cosmos-sdk/x/stake/client/rest"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
storeAcc = "acc"
|
||||
storeSlashing = "slashing"
|
||||
storeStake = "stake"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
rootCmd = &cobra.Command{
|
||||
|
@ -34,6 +45,17 @@ func main() {
|
|||
// get the codec
|
||||
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
|
||||
// the below functions and eliminate global vars, like we do
|
||||
// with the cdc.
|
||||
|
@ -50,40 +72,39 @@ func main() {
|
|||
|
||||
// add query/post commands (custom to binary)
|
||||
rootCmd.AddCommand(
|
||||
client.GetCommands(
|
||||
stakecmd.GetCmdQueryValidator("stake", cdc),
|
||||
stakecmd.GetCmdQueryValidators("stake", cdc),
|
||||
stakecmd.GetCmdQueryValidatorUnbondingDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryValidatorRedelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryPool("stake", cdc),
|
||||
stakecmd.GetCmdQueryParams("stake", cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegations("stake", cdc),
|
||||
stakecmd.GetCmdQueryRedelegation("stake", cdc),
|
||||
stakecmd.GetCmdQueryRedelegations("stake", cdc),
|
||||
slashingcmd.GetCmdQuerySigningInfo("slashing", cdc),
|
||||
authcmd.GetAccountCmd("acc", cdc, types.GetAccountDecoder(cdc)),
|
||||
)...)
|
||||
stakecmd.GetCmdQueryValidator(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryValidators(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryValidatorUnbondingDelegations(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryValidatorRedelegations(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryDelegation(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryDelegations(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryPool(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryParams(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegation(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryUnbondingDelegations(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryRedelegation(storeStake, cdc),
|
||||
stakecmd.GetCmdQueryRedelegations(storeStake, cdc),
|
||||
slashingcmd.GetCmdQuerySigningInfo(storeSlashing, cdc),
|
||||
stakecmd.GetCmdQueryValidatorDelegations(storeStake, cdc),
|
||||
authcmd.GetAccountCmd(storeAcc, cdc),
|
||||
)
|
||||
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
bankcmd.SendTxCmd(cdc),
|
||||
ibccmd.IBCTransferCmd(cdc),
|
||||
ibccmd.IBCRelayCmd(cdc),
|
||||
stakecmd.GetCmdCreateValidator(cdc),
|
||||
stakecmd.GetCmdEditValidator(cdc),
|
||||
stakecmd.GetCmdDelegate(cdc),
|
||||
stakecmd.GetCmdUnbond("stake", cdc),
|
||||
stakecmd.GetCmdRedelegate("stake", cdc),
|
||||
stakecmd.GetCmdUnbond(storeStake, cdc),
|
||||
stakecmd.GetCmdRedelegate(storeStake, cdc),
|
||||
slashingcmd.GetCmdUnjail(cdc),
|
||||
)...)
|
||||
)
|
||||
|
||||
// add proxy, version and key info
|
||||
rootCmd.AddCommand(
|
||||
client.LineBreak,
|
||||
lcd.ServeCommand(cdc),
|
||||
rs.ServeCommand(),
|
||||
keys.Commands(),
|
||||
client.LineBreak,
|
||||
version.VersionCmd,
|
||||
|
@ -97,3 +118,13 @@ func main() {
|
|||
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")))
|
||||
}
|
||||
|
||||
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) {
|
||||
bapp := app.NewBasecoinApp(logger, db)
|
||||
return bapp.ExportAppStateAndValidators()
|
||||
|
|
|
@ -83,10 +83,10 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
|
|||
|
||||
// Add handlers.
|
||||
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper)
|
||||
app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.bankKeeper, app.RegisterCodespace(cool.DefaultCodespace))
|
||||
app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.bankKeeper, app.RegisterCodespace(pow.DefaultCodespace))
|
||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace))
|
||||
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper, app.RegisterCodespace(simplestake.DefaultCodespace))
|
||||
app.coolKeeper = cool.NewKeeper(app.capKeyMainStore, app.bankKeeper, cool.DefaultCodespace)
|
||||
app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), app.bankKeeper, pow.DefaultCodespace)
|
||||
app.ibcMapper = ibc.NewMapper(app.cdc, app.capKeyIBCStore, ibc.DefaultCodespace)
|
||||
app.stakeKeeper = simplestake.NewKeeper(app.capKeyStakingStore, app.bankKeeper, simplestake.DefaultCodespace)
|
||||
app.Router().
|
||||
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
|
||||
AddRoute("cool", cool.NewHandler(app.coolKeeper)).
|
||||
|
|
|
@ -13,11 +13,11 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
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"
|
||||
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/types"
|
||||
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"
|
||||
simplestakingcmd "github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/simplestake/client/cli"
|
||||
|
@ -31,6 +31,7 @@ var (
|
|||
Use: "democli",
|
||||
Short: "Democoin light-client",
|
||||
}
|
||||
storeAcc = "acc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -47,6 +48,10 @@ func main() {
|
|||
config.SetBech32PrefixForConsensusNode("democons", "democonspub")
|
||||
config.Seal()
|
||||
|
||||
rs := lcd.NewRestServer(cdc)
|
||||
|
||||
registerRoutes(rs)
|
||||
|
||||
// TODO: setup keybase, viper object, etc. to be passed into
|
||||
// the below functions and eliminate global vars, like we do
|
||||
// with the cdc
|
||||
|
@ -65,20 +70,13 @@ func main() {
|
|||
// add query/post commands (custom to binary)
|
||||
// start with commands common to basecoin
|
||||
rootCmd.AddCommand(
|
||||
client.GetCommands(
|
||||
authcmd.GetAccountCmd("acc", cdc, types.GetAccountDecoder(cdc)),
|
||||
)...)
|
||||
authcmd.GetAccountCmd(storeAcc, cdc),
|
||||
)
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
bankcmd.SendTxCmd(cdc),
|
||||
)...)
|
||||
)
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCTransferCmd(cdc),
|
||||
)...)
|
||||
rootCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCRelayCmd(cdc),
|
||||
simplestakingcmd.BondTxCmd(cdc),
|
||||
)...)
|
||||
rootCmd.AddCommand(
|
||||
|
@ -96,7 +94,7 @@ func main() {
|
|||
// add proxy, version and key info
|
||||
rootCmd.AddCommand(
|
||||
client.LineBreak,
|
||||
lcd.ServeCommand(cdc),
|
||||
rs.ServeCommand(),
|
||||
keys.Commands(),
|
||||
client.LineBreak,
|
||||
version.VersionCmd,
|
||||
|
@ -110,3 +108,11 @@ func main() {
|
|||
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"
|
||||
)
|
||||
|
||||
|
||||
// coolGenAppParams sets up the app_state and appends the cool app state
|
||||
func CoolAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
dapp := app.NewDemocoinApp(logger, db)
|
||||
return dapp.ExportAppStateAndValidators()
|
||||
|
|
|
@ -50,7 +50,7 @@ func getMockApp(t *testing.T) *mock.App {
|
|||
RegisterCodec(mapp.Cdc)
|
||||
keyCool := sdk.NewKVStoreKey("cool")
|
||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper)
|
||||
keeper := NewKeeper(keyCool, bankKeeper, mapp.RegisterCodespace(DefaultCodespace))
|
||||
keeper := NewKeeper(keyCool, bankKeeper, DefaultCodespace)
|
||||
mapp.Router().AddRoute("cool", NewHandler(keeper))
|
||||
|
||||
mapp.SetInitChainer(getInitChainer(mapp, keeper, "ice-cold"))
|
||||
|
@ -88,17 +88,17 @@ func TestMsgQuiz(t *testing.T) {
|
|||
require.Equal(t, acc1, res1)
|
||||
|
||||
// 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{quizMsg1}, []int64{0}, []int64{1}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{2}, false, false, priv1) // result without reward
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{3}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"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{quizMsg1}, []int64{0}, []int64{5}, false, false, priv1) // the same answer will nolonger do!
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"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.CheckBalance(t, mapp, addr1, sdk.Coins{{"badvibesonly", sdk.NewInt(69)}, {"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{setTrendMsg1}, []uint64{0}, []uint64{0}, 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{sdk.NewCoin("icecold", sdk.NewInt(69))})
|
||||
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{sdk.NewCoin("icecold", sdk.NewInt(69))})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []uint64{0}, []uint64{3}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(138))})
|
||||
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}, []uint64{0}, []uint64{5}, false, false, priv1) // the same answer will nolonger do!
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("icecold", sdk.NewInt(138))})
|
||||
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{sdk.NewCoin("badvibesonly", sdk.NewInt(69)), sdk.NewCoin("icecold", sdk.NewInt(138))})
|
||||
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/docs/examples/democoin/x/cool"
|
||||
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"
|
||||
)
|
||||
|
||||
|
@ -22,7 +21,7 @@ func QuizTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
|
@ -46,7 +45,7 @@ func SetTrendTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
// Cool errors reserve 400 ~ 499.
|
||||
const (
|
||||
DefaultCodespace sdk.CodespaceType = 6
|
||||
DefaultCodespace sdk.CodespaceType = "cool"
|
||||
|
||||
// Cool module reserves error 400-499 lawl
|
||||
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)
|
||||
if err != nil {
|
||||
return sdk.Result{
|
||||
Code: sdk.ABCICodeOK,
|
||||
Code: sdk.CodeOK,
|
||||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func getMockApp(t *testing.T) *mock.App {
|
|||
keyPOW := sdk.NewKVStoreKey("pow")
|
||||
bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper)
|
||||
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.SetInitChainer(getInitChainer(mapp, keeper))
|
||||
|
@ -74,13 +74,13 @@ func TestMsgMine(t *testing.T) {
|
|||
|
||||
// Mine and check for reward
|
||||
mineMsg1 := GenerateMsgMine(addr1, 1, 2)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []int64{0}, []int64{0}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(1)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []uint64{0}, []uint64{0}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("pow", sdk.NewInt(1))})
|
||||
// Mine again and check for reward
|
||||
mineMsg2 := GenerateMsgMine(addr1, 2, 3)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []uint64{0}, []uint64{1}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewCoin("pow", sdk.NewInt(2))})
|
||||
// Mine again - should be invalid
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, false, false, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []uint64{0}, []uint64{1}, false, false, priv1)
|
||||
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/docs/examples/democoin/x/pow"
|
||||
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"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -24,7 +23,7 @@ func MineCmd(cdc *codec.Codec) *cobra.Command {
|
|||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
|
|
|
@ -9,7 +9,7 @@ type CodeType = sdk.CodeType
|
|||
|
||||
// POW errors reserve 200 ~ 299
|
||||
const (
|
||||
DefaultCodespace sdk.CodespaceType = 5
|
||||
DefaultCodespace sdk.CodespaceType = "pow"
|
||||
CodeInvalidDifficulty CodeType = 201
|
||||
CodeNonexistentDifficulty CodeType = 202
|
||||
CodeNonexistentReward CodeType = 203
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/docs/examples/democoin/x/simplestake"
|
||||
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"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -32,7 +31,7 @@ func BondTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
// simple stake errors reserve 300 ~ 399.
|
||||
const (
|
||||
DefaultCodespace sdk.CodespaceType = 4
|
||||
DefaultCodespace sdk.CodespaceType = moduleName
|
||||
|
||||
// simplestake errors reserve 300 - 399.
|
||||
CodeEmptyValidator sdk.CodeType = 300
|
||||
|
|
|
@ -22,12 +22,12 @@ func handleMsgBond() sdk.Result {
|
|||
// Removed ValidatorSet from result because it does not get used.
|
||||
// TODO: Implement correct bond/unbond handling
|
||||
return sdk.Result{
|
||||
Code: sdk.ABCICodeOK,
|
||||
Code: sdk.CodeOK,
|
||||
}
|
||||
}
|
||||
|
||||
func handleMsgUnbond() 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`
|
||||
- Used to receive funds
|
||||
- e.g. `cosmos15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc`
|
||||
|
||||
* `cosmosvaloper`
|
||||
* Used to associate a validator to it's operator
|
||||
* Used to invoke staking commands
|
||||
* e.g. `cosmosvaloper1carzvgq3e6y3z5kz5y6gxp3wpy3qdrv928vyah`
|
||||
- Used to associate a validator to it's operator
|
||||
- Used to invoke staking commands
|
||||
- e.g. `cosmosvaloper1carzvgq3e6y3z5kz5y6gxp3wpy3qdrv928vyah`
|
||||
|
||||
- `cosmospub`
|
||||
- Derived from account keys generated by `gaiacli keys add`
|
||||
- e.g. `cosmospub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm`
|
||||
|
@ -72,7 +74,7 @@ View the validator pubkey for your node by typing:
|
|||
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
|
||||
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
|
||||
|
||||
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
|
||||
gaiacli tx stake delegate \
|
||||
|
@ -367,6 +369,7 @@ With the `pool` command you will get the values for:
|
|||
##### Query Delegations To Validator
|
||||
|
||||
You can also query all of the delegations to a particular validator:
|
||||
|
||||
```bash
|
||||
gaiacli query delegations-to <account_cosmosval>
|
||||
```
|
||||
|
@ -418,7 +421,7 @@ Or query all available 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
|
||||
|
||||
|
@ -447,7 +450,7 @@ You can also query a deposit submitted by a specific address:
|
|||
```bash
|
||||
gaiacli query gov deposit \
|
||||
--proposal-id=<proposal_id> \
|
||||
--depositer=<account_cosmos>
|
||||
--depositor=<account_cosmos>
|
||||
```
|
||||
|
||||
#### 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):
|
||||
|
||||
```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
|
||||
|
|
|
@ -63,7 +63,7 @@ principle:
|
|||
type AppAccount struct {...}
|
||||
var account := &AppAccount{
|
||||
Address: pub.Address(),
|
||||
Coins: sdk.Coins{{"ATM", 100}},
|
||||
Coins: sdk.Coins{sdk.NewInt64Coin("ATM", 100)},
|
||||
}
|
||||
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.
|
||||
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.
|
||||
The BaseApp is composed of many internal components. Some of the most important
|
||||
include the `CommitMultiStore` and its internal state. The internal state is
|
||||
essentially two sub-states, both of which are used for transaction execution
|
||||
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
|
||||
need to be fully executed.
|
||||
The 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.
|
||||
|
||||
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:
|
||||
* 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
|
||||
|
||||
|
|
|
@ -68,8 +68,8 @@ const (
|
|||
|
||||
```go
|
||||
type Deposit struct {
|
||||
Amount sdk.Coins // Amount of coins deposited by depositer
|
||||
Depositer crypto.address // Address of depositer
|
||||
Amount sdk.Coins // Amount of coins deposited by depositor
|
||||
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
|
||||
// refund deposits (non-voters already punished)
|
||||
proposal.CurrentStatus = ProposalStatusAccepted
|
||||
for each (amount, depositer) in proposal.Deposits
|
||||
depositer.AtomBalance += amount
|
||||
for each (amount, depositor) in proposal.Deposits
|
||||
depositor.AtomBalance += amount
|
||||
|
||||
else
|
||||
// proposal was rejected
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
# 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
|
||||
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) {
|
||||
```
|
||||
NextInflationRate(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
||||
inflationRateChangePerYear = (1 - bondedRatio/params.GoalBonded) * params.InflationRateChange
|
||||
inflationRateChange = inflationRateChangePerYear/hrsPerYr
|
||||
|
||||
|
@ -26,3 +26,25 @@ NextInflation(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
|||
}
|
||||
|
||||
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
|
||||
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
|
||||
AnnualProvisions sdk.Dec // current annual exptected provisions
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -26,6 +27,7 @@ type Params struct {
|
|||
InflationMax sdk.Dec // maximum inflation rate
|
||||
InflationMin sdk.Dec // minimum inflation rate
|
||||
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.
|
||||
|
||||
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
|
||||
// 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) {
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
const (
|
||||
flagHeight = "height"
|
||||
flagForZeroHeight = "for-zero-height"
|
||||
)
|
||||
|
||||
// ExportCmd dumps app state to JSON.
|
||||
|
@ -50,7 +51,8 @@ func ExportCmd(ctx *Context, cdc *codec.Codec, appExporter AppExporter) *cobra.C
|
|||
return err
|
||||
}
|
||||
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 {
|
||||
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().Bool(flagForZeroHeight, false, "Export state to start at height zero (perform preproccessing)")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
|
||||
// SimpleGenTx is a simple genesis tx
|
||||
type SimpleGenTx struct {
|
||||
Addr sdk.AccAddress `json:"addr"`
|
||||
|
@ -23,7 +22,6 @@ type SimpleGenTx struct {
|
|||
|
||||
//_____________________________________________________________________
|
||||
|
||||
|
||||
// Generate a genesis transaction
|
||||
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (
|
||||
appGenTx, cliPrint json.RawMessage, validator types.GenesisValidator, err error) {
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
|
||||
// cacheMultiStore holds many cache-wrapped stores.
|
||||
// Implements MultiStore.
|
||||
// NOTE: a cacheMultiStore (and MultiStores in general) should never expose the
|
||||
// keys for the substores.
|
||||
type cacheMultiStore struct {
|
||||
db CacheKVStore
|
||||
stores map[StoreKey]CacheWrap
|
||||
|
|
|
@ -73,15 +73,15 @@ func testGasKVStoreWrap(t *testing.T, store KVStore) {
|
|||
meter := sdk.NewGasMeter(10000)
|
||||
|
||||
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"))
|
||||
require.Equal(t, int64(10), meter.GasConsumed())
|
||||
require.Equal(t, uint64(10), meter.GasConsumed())
|
||||
|
||||
store = store.Gas(meter, sdk.GasConfig{HasCost: 20})
|
||||
|
||||
store.Has([]byte("key"))
|
||||
require.Equal(t, int64(40), meter.GasConsumed())
|
||||
require.Equal(t, uint64(40), meter.GasConsumed())
|
||||
}
|
||||
|
||||
func TestGasKVStoreWrap(t *testing.T) {
|
||||
|
|
|
@ -230,13 +230,19 @@ func (rs *rootMultiStore) CacheMultiStore() CacheMultiStore {
|
|||
}
|
||||
|
||||
// Implements MultiStore.
|
||||
// If the store does not exist, panics.
|
||||
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
|
||||
// rootMultiStore, a wrapped TraceKVStore will be returned with the given
|
||||
// tracer, otherwise, the original KVStore will be returned.
|
||||
// If the store does not exist, panics.
|
||||
func (rs *rootMultiStore) GetKVStore(key StoreKey) KVStore {
|
||||
store := rs.stores[key].(KVStore)
|
||||
|
||||
|
|
|
@ -156,34 +156,37 @@ func TestMultiStoreQuery(t *testing.T) {
|
|||
// Test bad path.
|
||||
query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
|
||||
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"
|
||||
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.
|
||||
query.Path = "/garbage/key"
|
||||
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.
|
||||
query.Path = "/store1/key"
|
||||
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)
|
||||
|
||||
// Test valid but empty query.
|
||||
query.Path = "/store2/key"
|
||||
query.Prove = true
|
||||
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)
|
||||
|
||||
// Test store2 data.
|
||||
query.Data = k2
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
324
types/coin.go
324
types/coin.go
|
@ -4,23 +4,41 @@ import (
|
|||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"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 {
|
||||
Denom string `json:"denom"`
|
||||
|
||||
// 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 {
|
||||
if amount.LT(ZeroInt()) {
|
||||
panic(fmt.Sprintf("negative coin amount: %v\n", amount))
|
||||
}
|
||||
|
||||
return Coin{
|
||||
Denom: denom,
|
||||
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 {
|
||||
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))
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
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 is a set of Coin, one per currency
|
||||
|
@ -101,127 +132,157 @@ func (coins Coins) String() string {
|
|||
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 {
|
||||
switch len(coins) {
|
||||
case 0:
|
||||
return true
|
||||
case 1:
|
||||
return !coins[0].IsZero()
|
||||
return coins[0].IsPositive()
|
||||
default:
|
||||
lowDenom := coins[0].Denom
|
||||
|
||||
for _, coin := range coins[1:] {
|
||||
if coin.Denom <= lowDenom {
|
||||
return false
|
||||
}
|
||||
if coin.IsZero() {
|
||||
if !coin.IsPositive() {
|
||||
return false
|
||||
}
|
||||
|
||||
// we compare each coin against the last denom
|
||||
lowDenom = coin.Denom
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Plus combines two sets of coins
|
||||
// CONTRACT: Plus will never return Coins where one Coin has a 0 amount.
|
||||
// Plus adds two sets of coins.
|
||||
//
|
||||
// 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 {
|
||||
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)
|
||||
indexA, indexB := 0, 0
|
||||
lenA, lenB := len(coins), len(coinsB)
|
||||
|
||||
for {
|
||||
if indexA == lenA {
|
||||
if indexB == lenB {
|
||||
// return nil coins if both sets are empty
|
||||
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 {
|
||||
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]
|
||||
|
||||
switch strings.Compare(coinA.Denom, coinB.Denom) {
|
||||
case -1:
|
||||
if coinA.IsZero() {
|
||||
// ignore 0 sum coin type
|
||||
} else {
|
||||
case -1: // coin A denom < coin B denom
|
||||
if !coinA.IsZero() {
|
||||
sum = append(sum, coinA)
|
||||
}
|
||||
|
||||
indexA++
|
||||
case 0:
|
||||
if coinA.Amount.Add(coinB.Amount).IsZero() {
|
||||
// ignore 0 sum coin type
|
||||
} else {
|
||||
sum = append(sum, coinA.Plus(coinB))
|
||||
|
||||
case 0: // coin A denom == coin B denom
|
||||
res := coinA.Plus(coinB)
|
||||
if !res.IsZero() {
|
||||
sum = append(sum, res)
|
||||
}
|
||||
|
||||
indexA++
|
||||
indexB++
|
||||
case 1:
|
||||
if coinB.IsZero() {
|
||||
// ignore 0 sum coin type
|
||||
} else {
|
||||
|
||||
case 1: // coin A denom > coin B denom
|
||||
if !coinB.IsZero() {
|
||||
sum = append(sum, coinB)
|
||||
}
|
||||
|
||||
indexB++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Negative returns a set of coins with all amount negative
|
||||
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
|
||||
}
|
||||
|
||||
// Minus subtracts a set of coins from another (adds the inverse)
|
||||
// Minus subtracts a set of coins from another.
|
||||
//
|
||||
// e.g.
|
||||
// {2A, 3B} - {A} = {A, 3B}
|
||||
// {2A} - {0B} = {2A}
|
||||
// {A, B} - {A} = {B}
|
||||
//
|
||||
// CONTRACT: Minus will never return Coins where one Coin has a non-positive
|
||||
// amount. In otherwords, IsValid will always return true.
|
||||
func (coins Coins) Minus(coinsB Coins) Coins {
|
||||
return coins.Plus(coinsB.Negative())
|
||||
diff, hasNeg := coins.SafeMinus(coinsB)
|
||||
if hasNeg {
|
||||
panic("negative coin amount")
|
||||
}
|
||||
|
||||
// IsAllGT returns True iff for every denom in coins, the denom is present at a
|
||||
return diff
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (coins Coins) IsAllGT(coinsB Coins) bool {
|
||||
diff := coins.Minus(coinsB)
|
||||
diff, _ := coins.SafeMinus(coinsB)
|
||||
if len(diff) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
return diff.IsPositive()
|
||||
}
|
||||
|
||||
// IsAllGTE returns True iff for every denom in coins, the denom is present at an
|
||||
// equal or greater amount in coinsB.
|
||||
// IsAllGTE returns true iff for every denom in coins, the denom is present at
|
||||
// an equal or greater amount in coinsB.
|
||||
func (coins Coins) IsAllGTE(coinsB Coins) bool {
|
||||
diff := coins.Minus(coinsB)
|
||||
diff, _ := coins.SafeMinus(coinsB)
|
||||
if len(diff) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return diff.IsNotNegative()
|
||||
}
|
||||
|
||||
// IsAllLT returns True iff for every denom in coins, the denom is present at
|
||||
// a smaller amount in coinsB.
|
||||
func (coins Coins) IsAllLT(coinsB Coins) bool {
|
||||
diff := coinsB.Minus(coins)
|
||||
if len(diff) == 0 {
|
||||
return false
|
||||
}
|
||||
return diff.IsPositive()
|
||||
return coinsB.IsAllGT(coins)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (coins Coins) IsAllLTE(coinsB Coins) bool {
|
||||
diff := coinsB.Minus(coins)
|
||||
if len(diff) == 0 {
|
||||
return true
|
||||
}
|
||||
return diff.IsNotNegative()
|
||||
return coinsB.IsAllGTE(coins)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
return false
|
||||
}
|
||||
|
||||
coins = coins.Sort()
|
||||
coinsB = coinsB.Sort()
|
||||
|
||||
for i := 0; i < len(coins); i++ {
|
||||
if coins[i].Denom != coinsB[i].Denom || !coins[i].Amount.Equal(coinsB[i].Amount) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IsPositive returns true if there is at least one coin, and all
|
||||
// currencies have a positive value
|
||||
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 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
|
||||
// Empty returns true if there are no coins and false otherwise.
|
||||
func (coins Coins) Empty() bool {
|
||||
return len(coins) == 0
|
||||
}
|
||||
|
||||
// Returns the amount of a denom from coins
|
||||
|
@ -280,15 +323,18 @@ func (coins Coins) AmountOf(denom string) Int {
|
|||
switch len(coins) {
|
||||
case 0:
|
||||
return ZeroInt()
|
||||
|
||||
case 1:
|
||||
coin := coins[0]
|
||||
if coin.Denom == denom {
|
||||
return coin.Amount
|
||||
}
|
||||
return ZeroInt()
|
||||
|
||||
default:
|
||||
midIdx := len(coins) / 2 // 2:1, 3:1, 4:2
|
||||
coin := coins[midIdx]
|
||||
|
||||
if denom < coin.Denom {
|
||||
return coins[:midIdx].AmountOf(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
|
||||
|
||||
//nolint
|
||||
|
@ -315,7 +429,7 @@ func (coins Coins) Sort() Coins {
|
|||
return coins
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// Parsing
|
||||
|
||||
var (
|
||||
|
@ -333,17 +447,17 @@ func ParseCoin(coinStr string) (coin Coin, err error) {
|
|||
|
||||
matches := reCoin.FindStringSubmatch(coinStr)
|
||||
if matches == nil {
|
||||
err = fmt.Errorf("invalid coin expression: %s", coinStr)
|
||||
return
|
||||
return Coin{}, fmt.Errorf("invalid coin expression: %s", coinStr)
|
||||
}
|
||||
|
||||
denomStr, amountStr := matches[2], matches[1]
|
||||
|
||||
amount, err := strconv.Atoi(amountStr)
|
||||
if err != nil {
|
||||
return
|
||||
amount, ok := NewIntFromString(amountStr)
|
||||
if !ok {
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIsPositiveCoin(t *testing.T) {
|
||||
cases := []struct {
|
||||
inputOne Coin
|
||||
expected bool
|
||||
}{
|
||||
{NewInt64Coin("A", 1), true},
|
||||
{NewInt64Coin("A", 0), false},
|
||||
{NewInt64Coin("a", -1), false},
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// Coin tests
|
||||
|
||||
for tcIndex, tc := range cases {
|
||||
res := tc.inputOne.IsPositive()
|
||||
require.Equal(t, tc.expected, res, "%s positivity is incorrect, tc #%d", tc.inputOne.String(), tcIndex)
|
||||
}
|
||||
}
|
||||
|
||||
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 TestCoin(t *testing.T) {
|
||||
require.Panics(t, func() { NewInt64Coin("A", -1) })
|
||||
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 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), false},
|
||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
||||
{NewInt64Coin("stake", 1), NewInt64Coin("stake", 10), true},
|
||||
{NewInt64Coin("stake", -11), NewInt64Coin("stake", 10), true},
|
||||
{NewInt64Coin("steak", 1), NewInt64Coin("steak", 10), true},
|
||||
}
|
||||
|
||||
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) {
|
||||
cases := []struct {
|
||||
inputOne Coin
|
||||
|
@ -67,8 +115,7 @@ func TestIsGTECoin(t *testing.T) {
|
|||
}{
|
||||
{NewInt64Coin("A", 1), 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 {
|
||||
|
@ -85,7 +132,6 @@ func TestIsLTCoin(t *testing.T) {
|
|||
}{
|
||||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), false},
|
||||
{NewInt64Coin("A", 2), NewInt64Coin("A", 1), false},
|
||||
{NewInt64Coin("A", -1), NewInt64Coin("A", 5), true},
|
||||
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), false},
|
||||
{NewInt64Coin("a", 1), NewInt64Coin("b", 1), false},
|
||||
{NewInt64Coin("a", 1), NewInt64Coin("a", 1), false},
|
||||
|
@ -98,76 +144,18 @@ func TestIsLTCoin(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("stake", 1), NewInt64Coin("stake", 10), false},
|
||||
{NewInt64Coin("stake", -11), NewInt64Coin("stake", 10), false},
|
||||
func TestCoinIsZero(t *testing.T) {
|
||||
coin := NewInt64Coin("A", 0)
|
||||
res := coin.IsZero()
|
||||
require.True(t, res)
|
||||
|
||||
coin = NewInt64Coin("A", 1)
|
||||
res = coin.IsZero()
|
||||
require.False(t, res)
|
||||
}
|
||||
|
||||
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
|
||||
}{
|
||||
{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())
|
||||
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// Coins tests
|
||||
|
||||
func TestIsZeroCoins(t *testing.T) {
|
||||
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("A", 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)}, false},
|
||||
{Coins{NewInt64Coin("A", 0), NewInt64Coin("B", 1)}, Coins{NewInt64Coin("B", 1), NewInt64Coin("A", 0)}, true},
|
||||
}
|
||||
|
||||
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{
|
||||
{"GAS", NewInt(1)},
|
||||
{"MINERAL", NewInt(1)},
|
||||
{"TREE", NewInt(1)},
|
||||
}
|
||||
neg := good.Negative()
|
||||
sum := good.Plus(neg)
|
||||
empty := Coins{
|
||||
{"GOLD", NewInt(0)},
|
||||
}
|
||||
|
@ -228,6 +264,7 @@ func TestCoins(t *testing.T) {
|
|||
{"GAS", NewInt(1)},
|
||||
{"MINERAL", NewInt(1)},
|
||||
}
|
||||
|
||||
// both are after the first one, but the second and third are in the wrong order
|
||||
badSort2 := Coins{
|
||||
{"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.False(t, good.IsAllLT(empty), "Expected %v to be < %v", good, empty)
|
||||
assert.True(t, empty.IsAllLT(good), "Expected %v to be < %v", empty, good)
|
||||
assert.False(t, neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
|
||||
assert.Zero(t, len(sum), "Expected 0 coins")
|
||||
assert.False(t, badSort1.IsValid(), "Coins are not sorted")
|
||||
assert.False(t, badSort2.IsValid(), "Coins are not sorted")
|
||||
assert.False(t, badAmt.IsValid(), "Coins cannot include 0 amounts")
|
||||
assert.False(t, dup.IsValid(), "Duplicate coin")
|
||||
|
||||
}
|
||||
|
||||
func TestCoinsGT(t *testing.T) {
|
||||
|
@ -314,32 +348,6 @@ func TestCoinsLTE(t *testing.T) {
|
|||
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) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSortCoins(t *testing.T) {
|
||||
|
||||
good := Coins{
|
||||
NewInt64Coin("GAS", 1),
|
||||
NewInt64Coin("MINERAL", 1),
|
||||
|
@ -424,7 +430,6 @@ func TestSortCoins(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAmountOf(t *testing.T) {
|
||||
|
||||
case0 := Coins{}
|
||||
case1 := Coins{
|
||||
NewInt64Coin("", 0),
|
||||
|
@ -481,55 +486,3 @@ func TestAmountOf(t *testing.T) {
|
|||
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.
|
||||
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.
|
||||
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
|
||||
contextKeyBlockHeader
|
||||
contextKeyBlockHeight
|
||||
contextKeyConsensusParams
|
||||
contextKeyChainID
|
||||
contextKeyIsCheckTx
|
||||
contextKeyTxBytes
|
||||
contextKeyLogger
|
||||
contextKeyVoteInfos
|
||||
contextKeyGasMeter
|
||||
contextKeyBlockGasMeter
|
||||
contextKeyMinimumFees
|
||||
)
|
||||
|
||||
// NOTE: Do not expose MultiStore.
|
||||
// MultiStore exposes all the keys.
|
||||
// Instead, pass the context and the store key.
|
||||
func (c Context) multiStore() MultiStore {
|
||||
func (c Context) MultiStore() 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) ConsensusParams() abci.ConsensusParams {
|
||||
return c.Value(contextKeyConsensusParams).(abci.ConsensusParams)
|
||||
}
|
||||
|
||||
func (c Context) ChainID() string { return c.Value(contextKeyChainID).(string) }
|
||||
|
||||
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) BlockGasMeter() GasMeter { return c.Value(contextKeyBlockGasMeter).(GasMeter) }
|
||||
|
||||
func (c Context) IsCheckTx() bool { return c.Value(contextKeyIsCheckTx).(bool) }
|
||||
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
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) 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) WithBlockGasMeter(meter GasMeter) Context {
|
||||
return c.withValue(contextKeyBlockGasMeter, meter)
|
||||
}
|
||||
|
||||
func (c Context) WithIsCheckTx(isCheckTx bool) Context {
|
||||
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
|
||||
// written to the context when writeCache is called.
|
||||
func (c Context) CacheContext() (cc Context, writeCache func()) {
|
||||
cms := c.multiStore().CacheMultiStore()
|
||||
cms := c.MultiStore().CacheMultiStore()
|
||||
cc = c.WithMultiStore(cms)
|
||||
return cc, cms.Write
|
||||
}
|
||||
|
|
|
@ -172,10 +172,21 @@ func NewDecFromStr(str string) (d Dec, err Error) {
|
|||
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
|
||||
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) 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) 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
|
||||
|
@ -252,6 +263,14 @@ func (d Dec) IsInteger() bool {
|
|||
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 {
|
||||
bz, err := d.Int.MarshalText()
|
||||
if err != nil {
|
||||
|
|
|
@ -10,37 +10,22 @@ import (
|
|||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
// ABCICodeType - combined codetype / codespace
|
||||
type ABCICodeType uint32
|
||||
|
||||
// CodeType - code identifier within codespace
|
||||
type CodeType uint16
|
||||
// CodeType - ABCI code identifier within codespace
|
||||
type CodeType uint32
|
||||
|
||||
// CodespaceType - codespace identifier
|
||||
type CodespaceType uint16
|
||||
type CodespaceType string
|
||||
|
||||
// IsOK - is everything okay?
|
||||
func (code ABCICodeType) IsOK() bool {
|
||||
if code == ABCICodeOK {
|
||||
func (code CodeType) IsOK() bool {
|
||||
if code == CodeOK {
|
||||
return true
|
||||
}
|
||||
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
|
||||
const (
|
||||
// ABCI error codes
|
||||
ABCICodeOK ABCICodeType = 0
|
||||
|
||||
// Base error codes
|
||||
CodeOK CodeType = 0
|
||||
CodeInternal CodeType = 1
|
||||
|
@ -62,11 +47,8 @@ const (
|
|||
// CodespaceRoot is a codespace for error codes in this file only.
|
||||
// Notice that 0 is an "unset" codespace, which can be overridden with
|
||||
// Error.WithDefaultCodespace().
|
||||
CodespaceUndefined CodespaceType = 0
|
||||
CodespaceRoot CodespaceType = 1
|
||||
|
||||
// Maximum reservable codespace (2^16 - 1)
|
||||
MaximumCodespace CodespaceType = 65535
|
||||
CodespaceUndefined CodespaceType = ""
|
||||
CodespaceRoot CodespaceType = "sdk"
|
||||
)
|
||||
|
||||
func unknownCodeMsg(code CodeType) string {
|
||||
|
@ -185,7 +167,6 @@ type Error interface {
|
|||
Code() CodeType
|
||||
Codespace() CodespaceType
|
||||
ABCILog() string
|
||||
ABCICode() ABCICodeType
|
||||
Result() Result
|
||||
QueryResult() abci.ResponseQuery
|
||||
}
|
||||
|
@ -239,17 +220,12 @@ func (err *sdkError) TraceSDK(format string, args ...interface{}) Error {
|
|||
// Implements ABCIError.
|
||||
func (err *sdkError) Error() string {
|
||||
return fmt.Sprintf(`ERROR:
|
||||
Codespace: %d
|
||||
Codespace: %s
|
||||
Code: %d
|
||||
Message: %#v
|
||||
`, err.codespace, err.code, err.cmnError.Error())
|
||||
}
|
||||
|
||||
// Implements ABCIError.
|
||||
func (err *sdkError) ABCICode() ABCICodeType {
|
||||
return ToABCICode(err.codespace, err.code)
|
||||
}
|
||||
|
||||
// Implements Error.
|
||||
func (err *sdkError) Codespace() CodespaceType {
|
||||
return err.codespace
|
||||
|
@ -267,7 +243,6 @@ func (err *sdkError) ABCILog() string {
|
|||
jsonErr := humanReadableError{
|
||||
Codespace: err.codespace,
|
||||
Code: err.code,
|
||||
ABCICode: err.ABCICode(),
|
||||
Message: errMsg,
|
||||
}
|
||||
bz, er := cdc.MarshalJSON(jsonErr)
|
||||
|
@ -280,7 +255,8 @@ func (err *sdkError) ABCILog() string {
|
|||
|
||||
func (err *sdkError) Result() Result {
|
||||
return Result{
|
||||
Code: err.ABCICode(),
|
||||
Code: err.Code(),
|
||||
Codespace: err.Codespace(),
|
||||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
|
@ -288,7 +264,8 @@ func (err *sdkError) Result() Result {
|
|||
// QueryResult allows us to return sdk.Error.QueryResult() in query responses
|
||||
func (err *sdkError) QueryResult() abci.ResponseQuery {
|
||||
return abci.ResponseQuery{
|
||||
Code: uint32(err.ABCICode()),
|
||||
Code: uint32(err.Code()),
|
||||
Codespace: string(err.Codespace()),
|
||||
Log: err.ABCILog(),
|
||||
}
|
||||
}
|
||||
|
@ -324,6 +301,5 @@ func mustGetMsgIndex(abciLog string) int {
|
|||
type humanReadableError struct {
|
||||
Codespace CodespaceType `json:"codespace"`
|
||||
Code CodeType `json:"code"`
|
||||
ABCICode ABCICodeType `json:"abci_code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ var errFns = []errFn{
|
|||
}
|
||||
|
||||
func TestCodeType(t *testing.T) {
|
||||
require.True(t, ABCICodeOK.IsOK())
|
||||
require.True(t, CodeOK.IsOK())
|
||||
|
||||
for tcnum, c := range codeTypes {
|
||||
msg := CodeToDefaultMsg(c)
|
||||
|
@ -59,12 +59,9 @@ func TestErrFn(t *testing.T) {
|
|||
codeType := codeTypes[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.Result().Code, ToABCICode(CodespaceRoot, codeType), "Err function expected to return proper ABCICode. 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().Code, uint32(err.Code()), "Err function expected to return proper Code 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) {
|
||||
|
|
64
types/gas.go
64
types/gas.go
|
@ -18,17 +18,27 @@ var (
|
|||
)
|
||||
|
||||
// Gas measured by the SDK
|
||||
type Gas = int64
|
||||
type Gas = uint64
|
||||
|
||||
// ErrorOutOfGas defines an error thrown when an action results in out of gas.
|
||||
type ErrorOutOfGas struct {
|
||||
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
|
||||
type GasMeter interface {
|
||||
GasConsumed() Gas
|
||||
GasConsumedToLimit() Gas
|
||||
Limit() Gas
|
||||
ConsumeGas(amount Gas, descriptor string)
|
||||
IsPastLimit() bool
|
||||
IsOutOfGas() bool
|
||||
}
|
||||
|
||||
type basicGasMeter struct {
|
||||
|
@ -48,13 +58,39 @@ func (g *basicGasMeter) GasConsumed() Gas {
|
|||
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) {
|
||||
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 {
|
||||
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 {
|
||||
consumed Gas
|
||||
}
|
||||
|
@ -70,8 +106,30 @@ func (g *infiniteGasMeter) GasConsumed() Gas {
|
|||
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) {
|
||||
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
|
||||
|
|
|
@ -21,15 +21,24 @@ func TestGasMeter(t *testing.T) {
|
|||
|
||||
for tcnum, tc := range cases {
|
||||
meter := NewGasMeter(tc.limit)
|
||||
used := int64(0)
|
||||
used := uint64(0)
|
||||
|
||||
for unum, usage := range tc.usage {
|
||||
used += usage
|
||||
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.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.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
|
||||
|
||||
}
|
||||
|
|
53
types/int.go
53
types/int.go
|
@ -2,6 +2,7 @@ package types
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"math/big"
|
||||
|
@ -321,11 +322,11 @@ func NewUint(n uint64) Uint {
|
|||
|
||||
// NewUintFromBigUint constructs Uint from big.Uint
|
||||
func NewUintFromBigInt(i *big.Int) Uint {
|
||||
// Check overflow
|
||||
if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 {
|
||||
res := Uint{i}
|
||||
if UintOverflow(res) {
|
||||
panic("Uint overflow")
|
||||
}
|
||||
return Uint{i}
|
||||
return res
|
||||
}
|
||||
|
||||
// NewUintFromString constructs Uint from string
|
||||
|
@ -352,11 +353,12 @@ func NewUintWithDecimal(n uint64, dec int) Uint {
|
|||
i := new(big.Int)
|
||||
i.Mul(new(big.Int).SetUint64(n), exp)
|
||||
|
||||
// Check overflow
|
||||
if i.Sign() == -1 || i.Sign() == 1 && i.BitLen() > 256 {
|
||||
res := Uint{i}
|
||||
if UintOverflow(res) {
|
||||
panic("NewUintWithDecimal() out of bound")
|
||||
}
|
||||
return Uint{i}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// ZeroUint returns Uint value with zero
|
||||
|
@ -407,8 +409,7 @@ func (i Uint) LT(i2 Uint) bool {
|
|||
// Add adds Uint from another
|
||||
func (i Uint) Add(i2 Uint) (res Uint) {
|
||||
res = Uint{add(i.i, i2.i)}
|
||||
// Check overflow
|
||||
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
|
||||
if UintOverflow(res) {
|
||||
panic("Uint overflow")
|
||||
}
|
||||
return
|
||||
|
@ -422,13 +423,23 @@ func (i Uint) AddRaw(i2 uint64) Uint {
|
|||
// Sub subtracts Uint from another
|
||||
func (i Uint) Sub(i2 Uint) (res Uint) {
|
||||
res = Uint{sub(i.i, i2.i)}
|
||||
// Check overflow
|
||||
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
|
||||
if UintOverflow(res) {
|
||||
panic("Uint overflow")
|
||||
}
|
||||
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
|
||||
func (i Uint) SubRaw(i2 uint64) Uint {
|
||||
return i.Sub(NewUint(i2))
|
||||
|
@ -436,15 +447,15 @@ func (i Uint) SubRaw(i2 uint64) Uint {
|
|||
|
||||
// Mul multiples two Uints
|
||||
func (i Uint) Mul(i2 Uint) (res Uint) {
|
||||
// Check overflow
|
||||
if i.i.BitLen()+i2.i.BitLen()-1 > 256 {
|
||||
panic("Uint overflow")
|
||||
}
|
||||
|
||||
res = Uint{mul(i.i, i2.i)}
|
||||
// Check overflow
|
||||
if res.Sign() == -1 || res.Sign() == 1 && res.i.BitLen() > 256 {
|
||||
if UintOverflow(res) {
|
||||
panic("Uint overflow")
|
||||
}
|
||||
|
||||
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(...))
|
||||
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()
|
||||
|
|
|
@ -590,3 +590,53 @@ func TestEncodingTableUint(t *testing.T) {
|
|||
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 {
|
||||
|
||||
// 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 []byte
|
||||
|
@ -13,10 +16,10 @@ type Result struct {
|
|||
Log string
|
||||
|
||||
// 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 int64
|
||||
GasUsed uint64
|
||||
|
||||
// Tx fee amount and denom.
|
||||
FeeAmount int64
|
||||
|
|
|
@ -13,6 +13,6 @@ func TestResult(t *testing.T) {
|
|||
res.Data = []byte("data")
|
||||
require.True(t, res.IsOK())
|
||||
|
||||
res.Code = ABCICodeType(1)
|
||||
res.Code = CodeType(1)
|
||||
require.False(t, res.IsOK())
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ type MultiStore interface { //nolint
|
|||
CacheMultiStore() CacheMultiStore
|
||||
|
||||
// Convenience for fetching substores.
|
||||
// If the store does not exist, panics.
|
||||
GetStore(StoreKey) Store
|
||||
GetKVStore(StoreKey) KVStore
|
||||
|
||||
|
|
|
@ -32,9 +32,12 @@ type Msg interface {
|
|||
|
||||
// Transactions objects must fulfill the Tx
|
||||
type Tx interface {
|
||||
|
||||
// Gets the Msg.
|
||||
// Gets the all the transaction's messages.
|
||||
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.
|
||||
SetPubKey(crypto.PubKey) error
|
||||
|
||||
GetAccountNumber() int64
|
||||
SetAccountNumber(int64) error
|
||||
GetAccountNumber() uint64
|
||||
SetAccountNumber(uint64) error
|
||||
|
||||
GetSequence() int64
|
||||
SetSequence(int64) error
|
||||
GetSequence() uint64
|
||||
SetSequence(uint64) error
|
||||
|
||||
GetCoins() sdk.Coins
|
||||
SetCoins(sdk.Coins) error
|
||||
|
@ -48,8 +48,8 @@ type BaseAccount struct {
|
|||
Address sdk.AccAddress `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
PubKey crypto.PubKey `json:"public_key"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
Sequence uint64 `json:"sequence"`
|
||||
}
|
||||
|
||||
// Prototype function for BaseAccount
|
||||
|
@ -100,23 +100,23 @@ func (acc *BaseAccount) SetCoins(coins sdk.Coins) error {
|
|||
}
|
||||
|
||||
// Implements Account
|
||||
func (acc *BaseAccount) GetAccountNumber() int64 {
|
||||
func (acc *BaseAccount) GetAccountNumber() uint64 {
|
||||
return acc.AccountNumber
|
||||
}
|
||||
|
||||
// Implements Account
|
||||
func (acc *BaseAccount) SetAccountNumber(accNumber int64) error {
|
||||
func (acc *BaseAccount) SetAccountNumber(accNumber uint64) error {
|
||||
acc.AccountNumber = accNumber
|
||||
return nil
|
||||
}
|
||||
|
||||
// Implements sdk.Account.
|
||||
func (acc *BaseAccount) GetSequence() int64 {
|
||||
func (acc *BaseAccount) GetSequence() uint64 {
|
||||
return acc.Sequence
|
||||
}
|
||||
|
||||
// Implements sdk.Account.
|
||||
func (acc *BaseAccount) SetSequence(seq int64) error {
|
||||
func (acc *BaseAccount) SetSequence(seq uint64) error {
|
||||
acc.Sequence = seq
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ func TestBaseAccountSequence(t *testing.T) {
|
|||
_, _, addr := keyPubAddr()
|
||||
acc := NewBaseAccountWithAddress(addr)
|
||||
|
||||
seq := int64(7)
|
||||
seq := uint64(7)
|
||||
|
||||
err := acc.SetSequence(seq)
|
||||
require.Nil(t, err)
|
||||
|
@ -79,7 +79,7 @@ func TestBaseAccountMarshal(t *testing.T) {
|
|||
acc := NewBaseAccountWithAddress(addr)
|
||||
|
||||
someCoins := sdk.Coins{sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 246)}
|
||||
seq := int64(7)
|
||||
seq := uint64(7)
|
||||
|
||||
// set everything on the account
|
||||
err := acc.SetPubKey(pub)
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/multisig"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
)
|
||||
|
||||
|
@ -67,27 +66,18 @@ func NewAnteHandler(am AccountKeeper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
|||
}
|
||||
}()
|
||||
|
||||
err := validateBasic(stdTx)
|
||||
if err != nil {
|
||||
if err := tx.ValidateBasic(); err != nil {
|
||||
return newCtx, err.Result(), true
|
||||
}
|
||||
|
||||
// charge gas for the memo
|
||||
newCtx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo")
|
||||
|
||||
// stdSigs contains the sequence number, account number, and signatures
|
||||
stdSigs := stdTx.GetSignatures() // When simulating, this would just be a 0-length slice.
|
||||
// stdSigs contains the sequence number, account number, and signatures.
|
||||
// When simulating, this would just be a 0-length slice.
|
||||
stdSigs := stdTx.GetSignatures()
|
||||
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
|
||||
signBytesList := getSignBytesList(newCtx.ChainID(), stdTx, stdSigs)
|
||||
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) {
|
||||
accs = make([]Account, len(addrs))
|
||||
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
|
||||
gasFees := make(sdk.Coins, len(fees))
|
||||
|
||||
// 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++ {
|
||||
gasFees[i] = sdk.NewInt64Coin(fees[i].Denom, gasCost)
|
||||
gasFees[i] = sdk.NewInt64Coin(fees[i].Denom, int64(gasCost))
|
||||
}
|
||||
|
||||
return fees.Plus(gasFees)
|
||||
}
|
||||
|
||||
|
@ -277,23 +247,35 @@ func deductFees(acc Account, fee StdFee) (Account, sdk.Result) {
|
|||
coins := acc.GetCoins()
|
||||
feeAmount := fee.Amount
|
||||
|
||||
newCoins := coins.Minus(feeAmount)
|
||||
if !newCoins.IsNotNegative() {
|
||||
if !feeAmount.IsValid() {
|
||||
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)
|
||||
return nil, sdk.ErrInsufficientFunds(errMsg).Result()
|
||||
}
|
||||
|
||||
err := acc.SetCoins(newCoins)
|
||||
if err != nil {
|
||||
// Handle w/ #870
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return acc, sdk.Result{}
|
||||
}
|
||||
|
||||
func ensureSufficientMempoolFees(ctx sdk.Context, stdTx StdTx) sdk.Result {
|
||||
// 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.
|
||||
// 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)
|
||||
|
||||
// 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 {
|
||||
// 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 {
|
||||
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
}
|
||||
|
||||
return ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
|
||||
}
|
||||
|
||||
|
@ -322,15 +306,3 @@ func getSignBytesList(chainID string, stdTx StdTx, stdSigs []StdSignature) (sign
|
|||
}
|
||||
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) {
|
||||
_, result, abort := anteHandler(ctx, tx, simulate)
|
||||
require.False(t, abort)
|
||||
require.Equal(t, sdk.ABCICodeOK, result.Code)
|
||||
require.Equal(t, sdk.CodeOK, result.Code)
|
||||
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) {
|
||||
newCtx, result, abort := anteHandler(ctx, tx, simulate)
|
||||
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 {
|
||||
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))
|
||||
for i, priv := range privs {
|
||||
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
|
||||
}
|
||||
|
||||
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))
|
||||
for i, priv := range privs {
|
||||
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
|
||||
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))
|
||||
for i, priv := range privs {
|
||||
sig, err := priv.Sign(signBytes)
|
||||
|
@ -132,7 +133,7 @@ func TestAnteHandlerSigErrors(t *testing.T) {
|
|||
msgs := []sdk.Msg{msg1, msg2}
|
||||
|
||||
// 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.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)
|
||||
|
||||
// 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)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
||||
|
||||
// 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)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnknownAddress)
|
||||
|
||||
|
@ -192,30 +193,30 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
|
|||
msgs := []sdk.Msg{msg}
|
||||
|
||||
// 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)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
// new tx from wrong account number
|
||||
seqs = []int64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []int64{1}, seqs, fee)
|
||||
seqs = []uint64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
|
||||
// from correct account number
|
||||
seqs = []int64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []int64{0}, seqs, fee)
|
||||
seqs = []uint64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []uint64{0}, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
// new tx with another signer and incorrect account numbers
|
||||
msg1 := newTestMsg(addr1, addr2)
|
||||
msg2 := newTestMsg(addr2, addr1)
|
||||
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)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
|
||||
// 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)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
}
|
||||
|
@ -252,30 +253,30 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) {
|
|||
msgs := []sdk.Msg{msg}
|
||||
|
||||
// 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)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
// new tx from wrong account number
|
||||
seqs = []int64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []int64{1}, seqs, fee)
|
||||
seqs = []uint64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
|
||||
// from correct account number
|
||||
seqs = []int64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []int64{0}, seqs, fee)
|
||||
seqs = []uint64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []uint64{0}, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
// new tx with another signer and incorrect account numbers
|
||||
msg1 := newTestMsg(addr1, addr2)
|
||||
msg2 := newTestMsg(addr2, addr1)
|
||||
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)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
|
||||
// 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)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
}
|
||||
|
@ -316,7 +317,7 @@ func TestAnteHandlerSequences(t *testing.T) {
|
|||
msgs := []sdk.Msg{msg}
|
||||
|
||||
// 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)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
|
@ -324,7 +325,7 @@ func TestAnteHandlerSequences(t *testing.T) {
|
|||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
|
||||
// fix sequence, should pass
|
||||
seqs = []int64{1}
|
||||
seqs = []uint64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
|
@ -333,7 +334,7 @@ func TestAnteHandlerSequences(t *testing.T) {
|
|||
msg2 := newTestMsg(addr3, addr1)
|
||||
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)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
|
@ -343,18 +344,18 @@ func TestAnteHandlerSequences(t *testing.T) {
|
|||
// tx from just second signer with incorrect sequence fails
|
||||
msg = newTestMsg(addr2)
|
||||
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)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
|
||||
// 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)
|
||||
|
||||
// another tx from both of them that passes
|
||||
msg = newTestMsg(addr1, addr2)
|
||||
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)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
}
|
||||
|
@ -380,7 +381,7 @@ func TestAnteHandlerFees(t *testing.T) {
|
|||
// msg and signatures
|
||||
var tx sdk.Tx
|
||||
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()
|
||||
msgs := []sdk.Msg{msg}
|
||||
|
||||
|
@ -423,7 +424,7 @@ func TestAnteHandlerMemoGas(t *testing.T) {
|
|||
// msg and signatures
|
||||
var tx sdk.Tx
|
||||
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))
|
||||
|
||||
// tx does not have enough gas
|
||||
|
@ -482,19 +483,19 @@ func TestAnteHandlerMultiSigner(t *testing.T) {
|
|||
fee := newStdFee()
|
||||
|
||||
// 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")
|
||||
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
// 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)
|
||||
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)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
@ -531,7 +532,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
|||
fee3.Amount[0].Amount = fee3.Amount[0].Amount.AddRaw(100)
|
||||
|
||||
// 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)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
|
@ -541,8 +542,8 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
|||
|
||||
cases := []struct {
|
||||
chainID string
|
||||
accnum int64
|
||||
seq int64
|
||||
accnum uint64
|
||||
seq uint64
|
||||
fee StdFee
|
||||
msgs []sdk.Msg
|
||||
code sdk.CodeType
|
||||
|
@ -555,7 +556,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
|||
{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 {
|
||||
tx := newTestTxWithSignBytes(
|
||||
|
||||
|
@ -567,14 +568,14 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
|||
}
|
||||
|
||||
// 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)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
||||
|
||||
// test wrong signer if public doesn't exist
|
||||
msg = newTestMsg(addr2)
|
||||
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)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)
|
||||
|
||||
|
@ -608,7 +609,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
|||
// test good tx and set public key
|
||||
msg := newTestMsg(addr1)
|
||||
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()
|
||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
@ -619,7 +620,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
|||
// test public key not found
|
||||
msg = newTestMsg(addr2)
|
||||
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[0].PubKey = nil
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey)
|
||||
|
@ -628,7 +629,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
|||
require.Nil(t, acc2.GetPubKey())
|
||||
|
||||
// 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)
|
||||
|
||||
acc2 = mapper.GetAccount(ctx, addr2)
|
||||
|
@ -676,7 +677,7 @@ func TestConsumeSignatureVerificationGas(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
gasConsumed int64
|
||||
gasConsumed uint64
|
||||
wantPanic bool
|
||||
}{
|
||||
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), ed25519.GenPrivKey().PubKey()}, ed25519VerifyCost, false},
|
||||
|
@ -698,7 +699,7 @@ func TestConsumeSignatureVerificationGas(t *testing.T) {
|
|||
func TestAdjustFeesByGas(t *testing.T) {
|
||||
type args struct {
|
||||
fee sdk.Coins
|
||||
gas int64
|
||||
gas uint64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -707,7 +708,6 @@ func TestAdjustFeesByGas(t *testing.T) {
|
|||
}{
|
||||
{"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)}},
|
||||
{"negative coins", args{sdk.Coins{sdk.NewInt64Coin("A", -10), sdk.NewInt64Coin("B", 10)}, 10000}, sdk.Coins{sdk.NewInt64Coin("B", 20)}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -785,7 +785,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) {
|
|||
|
||||
// test rejection logic
|
||||
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)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeTooManySignatures)
|
||||
}
|
||||
|
|
|
@ -5,34 +5,17 @@ import (
|
|||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
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
|
||||
// account at a given address.
|
||||
// nolint: unparam
|
||||
func GetAccountCmd(storeName string, cdc *codec.Codec, decoder auth.AccountDecoder) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
func GetAccountCmd(storeName string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "account [address]",
|
||||
Short: "Query account balance",
|
||||
Args: cobra.ExactArgs(1),
|
||||
|
@ -47,9 +30,9 @@ func GetAccountCmd(storeName string, cdc *codec.Codec, decoder auth.AccountDecod
|
|||
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(decoder)
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
if err := cliCtx.EnsureAccountExistsFromAddr(key); err != nil {
|
||||
if err = cliCtx.EnsureAccountExistsFromAddr(key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -72,4 +55,7 @@ func GetAccountCmd(storeName string, cdc *codec.Codec, decoder auth.AccountDecod
|
|||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Add the flags here and return the command
|
||||
return client.GetCommands(cmd)[0]
|
||||
}
|
||||
|
|
|
@ -2,9 +2,8 @@ package cli
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/viper"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
|
@ -12,7 +11,9 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
|
@ -21,10 +22,11 @@ const (
|
|||
flagValidateSigs = "validate-signatures"
|
||||
flagOffline = "offline"
|
||||
flagSigOnly = "signature-only"
|
||||
flagOutfile = "output-document"
|
||||
)
|
||||
|
||||
// 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{
|
||||
Use: "sign <file>",
|
||||
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.
|
||||
Thus account number or sequence number lookups will not be performed and it is
|
||||
recommended to set such parameters manually.`,
|
||||
RunE: makeSignCmd(codec, decoder),
|
||||
RunE: makeSignCmd(codec),
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
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, "+
|
||||
"those who have already signed it, and make sure that signatures are in the correct order.")
|
||||
cmd.Flags().Bool(flagOffline, false, "Offline mode. Do not query local cache.")
|
||||
return cmd
|
||||
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) {
|
||||
stdTx, err := readAndUnmarshalStdTx(cdc, args[0])
|
||||
if err != nil {
|
||||
|
@ -72,7 +78,7 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
|
|||
if name == "" {
|
||||
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()
|
||||
|
||||
// if --signature-only is on, then override --append
|
||||
|
@ -104,9 +110,22 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func printSignatures(stdTx auth.StdTx) bool {
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
@ -17,11 +16,11 @@ import (
|
|||
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec, storeName string) {
|
||||
r.HandleFunc(
|
||||
"/auth/accounts/{address}",
|
||||
QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx),
|
||||
QueryAccountRequestHandlerFn(storeName, cdc, context.GetAccountDecoder(cdc), cliCtx),
|
||||
).Methods("GET")
|
||||
r.HandleFunc(
|
||||
"/bank/balances/{address}",
|
||||
QueryBalancesRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx),
|
||||
QueryBalancesRequestHandlerFn(storeName, cdc, context.GetAccountDecoder(cdc), cliCtx),
|
||||
).Methods("GET")
|
||||
r.HandleFunc(
|
||||
"/tx/sign",
|
||||
|
|
|
@ -18,8 +18,8 @@ type SignBody struct {
|
|||
LocalAccountName string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
ChainID string `json:"chain_id"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
Sequence uint64 `json:"sequence"`
|
||||
AppendSig bool `json:"append_sig"`
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
// it is signed. For use in the CLI.
|
||||
type StdSignMsg struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
AccountNumber uint64 `json:"account_number"`
|
||||
Sequence uint64 `json:"sequence"`
|
||||
Fee auth.StdFee `json:"fee"`
|
||||
Msgs []sdk.Msg `json:"msgs"`
|
||||
Memo string `json:"memo"`
|
||||
|
|
|
@ -14,9 +14,9 @@ import (
|
|||
// TxBuilder implements a transaction context created in SDK modules.
|
||||
type TxBuilder struct {
|
||||
Codec *codec.Codec
|
||||
AccountNumber int64
|
||||
Sequence int64
|
||||
Gas int64 // TODO: should this turn into uint64? requires further discussion - see #2173
|
||||
AccountNumber uint64
|
||||
Sequence uint64
|
||||
Gas uint64
|
||||
GasAdjustment float64
|
||||
SimulateGas bool
|
||||
ChainID string
|
||||
|
@ -38,10 +38,10 @@ func NewTxBuilderFromCLI() TxBuilder {
|
|||
|
||||
return TxBuilder{
|
||||
ChainID: chainID,
|
||||
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
|
||||
AccountNumber: uint64(viper.GetInt64(client.FlagAccountNumber)),
|
||||
Gas: client.GasFlagVar.Gas,
|
||||
GasAdjustment: viper.GetFloat64(client.FlagGasAdjustment),
|
||||
Sequence: viper.GetInt64(client.FlagSequence),
|
||||
Sequence: uint64(viper.GetInt64(client.FlagSequence)),
|
||||
SimulateGas: client.GasFlagVar.Simulate,
|
||||
Fee: viper.GetString(client.FlagFee),
|
||||
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.
|
||||
func (bldr TxBuilder) WithGas(gas int64) TxBuilder {
|
||||
func (bldr TxBuilder) WithGas(gas uint64) TxBuilder {
|
||||
bldr.Gas = gas
|
||||
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.
|
||||
func (bldr TxBuilder) WithSequence(sequence int64) TxBuilder {
|
||||
func (bldr TxBuilder) WithSequence(sequence uint64) TxBuilder {
|
||||
bldr.Sequence = sequence
|
||||
return bldr
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ func (bldr TxBuilder) WithMemo(memo string) TxBuilder {
|
|||
}
|
||||
|
||||
// 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
|
||||
return bldr
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -21,9 +21,9 @@ var (
|
|||
func TestTxBuilderBuild(t *testing.T) {
|
||||
type fields struct {
|
||||
Codec *codec.Codec
|
||||
AccountNumber int64
|
||||
Sequence int64
|
||||
Gas int64
|
||||
AccountNumber uint64
|
||||
Sequence uint64
|
||||
Gas uint64
|
||||
GasAdjustment float64
|
||||
SimulateGas bool
|
||||
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
|
||||
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)
|
||||
if acc == nil {
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
if acc == nil {
|
||||
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
|
||||
func (am AccountKeeper) GetNextAccountNumber(ctx sdk.Context) int64 {
|
||||
var accNumber int64
|
||||
func (am AccountKeeper) GetNextAccountNumber(ctx sdk.Context) uint64 {
|
||||
var accNumber uint64
|
||||
store := ctx.KVStore(am.key)
|
||||
bz := store.Get(globalAccountNumberKey)
|
||||
if bz == nil {
|
||||
|
|
|
@ -49,7 +49,7 @@ func TestAccountMapperGetSet(t *testing.T) {
|
|||
require.Nil(t, mapper.GetAccount(ctx, addr))
|
||||
|
||||
// set some values on the account and save it
|
||||
newSequence := int64(20)
|
||||
newSequence := uint64(20)
|
||||
acc.SetSequence(newSequence)
|
||||
mapper.SetAccount(ctx, acc)
|
||||
|
||||
|
@ -75,8 +75,8 @@ func TestAccountMapperRemoveAccount(t *testing.T) {
|
|||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||
|
||||
accSeq1 := int64(20)
|
||||
accSeq2 := int64(40)
|
||||
accSeq1 := uint64(20)
|
||||
accSeq2 := uint64(40)
|
||||
|
||||
acc1.SetSequence(accSeq1)
|
||||
acc2.SetSequence(accSeq2)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue