Merge develop

This commit is contained in:
Federico Kunze 2018-11-26 13:41:00 +01:00
commit 60fc7c7919
188 changed files with 4200 additions and 2453 deletions

View File

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

1
Gopkg.lock generated
View File

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

View File

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

View File

@ -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
* [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
- #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.
- #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

View File

@ -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,8 +379,9 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc
}
case "version":
return abci.ResponseQuery{
Code: uint32(sdk.ABCICodeOK),
Value: []byte(version.GetVersion()),
Code: uint32(sdk.CodeOK),
Codespace: string(sdk.CodespaceRoot),
Value: []byte(version.GetVersion()),
}
default:
result = sdk.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path)).Result()
@ -339,8 +390,9 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc
// Encode with json
value := codec.Cdc.MustMarshalBinaryLengthPrefixed(result)
return abci.ResponseQuery{
Code: uint32(sdk.ABCICodeOK),
Value: value,
Code: uint32(sdk.CodeOK),
Codespace: string(sdk.CodespaceRoot),
Value: value,
}
}
msg := "Expected second parameter to be either simulate or version, neither was present"
@ -392,6 +444,7 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
return sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult()
}
// 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()),
Log: err.ABCILog(),
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
}
@ -562,10 +630,11 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
// Set the final gas values.
result = sdk.Result{
Code: code,
Data: data,
Log: strings.Join(logs, "\n"),
GasUsed: ctx.GasMeter().GasConsumed(),
Code: code,
Codespace: codespace,
Data: data,
Log: strings.Join(logs, "\n"),
GasUsed: ctx.GasMeter().GasConsumed(),
// TODO: FeeAmount/FeeDenom
Tags: tags,
}
@ -575,7 +644,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (re
// Returns the applicantion's deliverState if app is in runTxModeDeliver,
// 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()

View File

@ -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)
@ -282,12 +284,24 @@ func TestInitChainer(t *testing.T) {
// Simple tx with a list of Msgs.
type txTest struct {
Msgs []sdk.Msg
Counter int64
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) GetMsgs() []sdk.Msg { return tx.Msgs }
func (tx txTest) ValidateBasic() sdk.Error { return nil }
const (
routeMsgCounter = "msgCounter"
@ -297,7 +311,8 @@ const (
// ValidateBasic() fails on negative counters.
// Otherwise it's up to the handlers
type msgCounter struct {
Counter int64
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()
}

View File

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

View File

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

View File

@ -17,25 +17,32 @@ const (
DefaultGasLimit = 200000
GasFlagSimulate = "simulate"
FlagUseLedger = "ledger"
FlagChainID = "chain-id"
FlagNode = "node"
FlagHeight = "height"
FlagGas = "gas"
FlagGasAdjustment = "gas-adjustment"
FlagTrustNode = "trust-node"
FlagFrom = "from"
FlagName = "name"
FlagAccountNumber = "account-number"
FlagSequence = "sequence"
FlagMemo = "memo"
FlagFee = "fee"
FlagAsync = "async"
FlagJson = "json"
FlagPrintResponse = "print-response"
FlagDryRun = "dry-run"
FlagGenerateOnly = "generate-only"
FlagIndentResponse = "indent"
FlagUseLedger = "ledger"
FlagChainID = "chain-id"
FlagNode = "node"
FlagHeight = "height"
FlagGas = "gas"
FlagGasAdjustment = "gas-adjustment"
FlagTrustNode = "trust-node"
FlagFrom = "from"
FlagName = "name"
FlagAccountNumber = "account-number"
FlagSequence = "sequence"
FlagMemo = "memo"
FlagFee = "fee"
FlagAsync = "async"
FlagJson = "json"
FlagPrintResponse = "print-response"
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

View File

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

View File

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

View File

@ -10,176 +10,169 @@ 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
log log.Logger
listener net.Listener
fingerprint string
}
// NewRestServer creates a new rest server instance
func NewRestServer(cdc *codec.Codec) *RestServer {
r := mux.NewRouter()
cliCtx := context.NewCLIContext().WithCodec(cdc)
// Register version methods on the router
r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET")
r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET")
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
return &RestServer{
Mux: r,
CliCtx: cliCtx,
Cdc: cdc,
log: logger,
}
}
func (rs *RestServer) setKeybase(kb keybase.Keybase) {
// If a keybase is passed in, set it and return
if kb != nil {
rs.KeyBase = kb
return
}
// Otherwise get the keybase and set it
kb, err := keys.GetKeyBase() //XXX
if err != nil {
fmt.Printf("Failed to open Keybase: %s, exiting...", err)
os.Exit(1)
}
rs.KeyBase = kb
}
// Start starts the rest server
func (rs *RestServer) Start(listenAddr string, sslHosts string,
certFile string, keyFile string, maxOpen int, insecure bool) (err error) {
server.TrapSignal(func() {
err := rs.listener.Close()
rs.log.Error("error closing listener", "err", err)
})
// TODO: re-enable insecure mode once #2715 has been addressed
if insecure {
fmt.Println(
"Insecure mode is temporarily disabled, please locally generate an " +
"SSL certificate to test. Support will be re-enabled soon!",
)
// listener, err = tmserver.StartHTTPServer(
// listenAddr, handler, logger,
// tmserver.Config{MaxOpenConnections: maxOpen},
// )
// if err != nil {
// return
// }
} else {
if certFile != "" {
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
err = validateCertKeyFiles(certFile, keyFile)
if err != nil {
return err
}
// cert/key pair is provided, read the fingerprint
rs.fingerprint, err = fingerprintFromFile(certFile)
if err != nil {
return err
}
} else {
// if certificate is not supplied, generate a self-signed one
certFile, keyFile, rs.fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
if err != nil {
return err
}
defer func() {
os.Remove(certFile)
os.Remove(keyFile)
}()
}
rs.listener, err = tmserver.StartHTTPAndTLSServer(
listenAddr, rs.Mux,
certFile, keyFile,
rs.log,
tmserver.Config{MaxOpenConnections: maxOpen},
)
if err != nil {
return
}
rs.log.Info(rs.fingerprint)
rs.log.Info("REST server started")
}
// logger.Info("REST server started")
return nil
}
// ServeCommand will generate a long-running rest server
// (aka Light Client Daemon) that exposes functionality similar
// to the cli, but over rest
func ServeCommand(cdc *codec.Codec) *cobra.Command {
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) {
listenAddr := viper.GetString(flagListenAddr)
handler := createHandler(cdc)
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))
registerSwaggerUI(handler)
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "rest-server")
maxOpen := viper.GetInt(flagMaxOpenConnections)
sslHosts := viper.GetString(flagSSLHosts)
certFile := viper.GetString(flagSSLCertFile)
keyFile := viper.GetString(flagSSLKeyFile)
var listener net.Listener
var fingerprint string
server.TrapSignal(func() {
err := listener.Close()
logger.Error("error closing listener", "err", err)
})
var cleanupFunc func()
// TODO: re-enable insecure mode once #2715 has been addressed
if viper.GetBool(flagInsecure) {
fmt.Println(
"Insecure mode is temporarily disabled, please locally generate an " +
"SSL certificate to test. Support will be re-enabled soon!",
)
// listener, err = tmserver.StartHTTPServer(
// listenAddr, handler, logger,
// tmserver.Config{MaxOpenConnections: maxOpen},
// )
// if err != nil {
// return
// }
} else {
if certFile != "" {
// validateCertKeyFiles() is needed to work around tendermint/tendermint#2460
err = validateCertKeyFiles(certFile, keyFile)
if err != nil {
return err
}
// cert/key pair is provided, read the fingerprint
fingerprint, err = fingerprintFromFile(certFile)
if err != nil {
return err
}
} else {
// if certificate is not supplied, generate a self-signed one
certFile, keyFile, fingerprint, err = genCertKeyFilesAndReturnFingerprint(sslHosts)
if err != nil {
return err
}
cleanupFunc = func() {
os.Remove(certFile)
os.Remove(keyFile)
}
defer cleanupFunc()
}
listener, err = tmserver.StartHTTPAndTLSServer(
listenAddr, handler,
certFile, keyFile,
logger,
tmserver.Config{MaxOpenConnections: maxOpen},
)
if err != nil {
return
}
logger.Info(fingerprint)
logger.Info("REST server started")
}
// logger.Info("REST server started")
return nil
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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

156
cmd/gaia/app/export.go Normal file
View File

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

View File

@ -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)
}
@ -279,11 +280,13 @@ 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},
coins := sdk.Coins{
sdk.NewCoin("fooToken", sdk.NewInt(1000)),
sdk.NewCoin(bondDenom, freeFermionsAcc),
}
coins.Sort()
accAuth.Coins = coins
return NewGenesisAccount(&accAuth)
}

View File

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

View File

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

View File

@ -1,64 +1,98 @@
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"
)
const (
storeAcc = "acc"
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",
}
storeAcc = "acc"
storeGov = "gov"
storeSlashing = "slashing"
storeStake = "stake"
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 {

View File

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

View File

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

View File

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

View File

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

View File

@ -25,14 +25,14 @@ func TestAddGenesisAccount(t *testing.T) {
}{
{
"valid account",
args{
app.GenesisState{},
addr1,
sdk.Coins{},
},
false},
args{
app.GenesisState{},
addr1,
sdk.Coins{},
},
false},
{"dup account", args{
app.GenesisState{Accounts: []app.GenesisAccount{app.GenesisAccount{Address:addr1}}},
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
addr1,
sdk.Coins{}}, true},
}

View File

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

View File

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

View File

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

View File

@ -12,7 +12,8 @@ import (
)
const (
app1Name = "App1"
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.

View File

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

View File

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

View File

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

View File

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

View File

@ -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),
slashingcmd.GetCmdUnjail(cdc),
)...)
bankcmd.SendTxCmd(cdc),
ibccmd.IBCTransferCmd(cdc),
ibccmd.IBCRelayCmd(cdc),
stakecmd.GetCmdCreateValidator(cdc),
stakecmd.GetCmdEditValidator(cdc),
stakecmd.GetCmdDelegate(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)
}

View File

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

View File

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

View File

@ -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(
bankcmd.SendTxCmd(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)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 \
@ -304,7 +306,7 @@ gaiacli tx stake redelegate \
--chain-id=<chain_id>
```
Here you can also redelegate a specific `shares-amount` or a `shares-fraction` with the corresponding flags.
Here you can also redelegate a specific `shares-amount` or a `shares-fraction` with the corresponding flags.
The redelegation will be automatically completed when the unbonding period has passed.
@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
Inflation sdk.Dec // current annual inflation rate
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
}
```

View File

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

View File

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

View File

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

View File

@ -14,7 +14,8 @@ import (
)
const (
flagHeight = "height"
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
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"`
Amount Int `json:"amount"`
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")
}
return diff
}
// IsAllGT returns True iff for every denom in coins, the denom is present at a
// SafeMinus performs the same arithmetic as Minus but returns a boolean if any
// negative coin amount was returned.
func (coins Coins) SafeMinus(coinsB Coins) (Coins, bool) {
diff := coins.safePlus(coinsB.negative())
return diff, !diff.IsNotNegative()
}
// IsAllGT returns true iff for every denom in coins, the denom is present at a
// greater amount in coinsB.
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.

View File

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

View File

@ -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)
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)
}
coin = NewInt64Coin("A", 1)
res = coin.IsZero()
require.False(t, res)
}
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))
}
}

View File

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

View File

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

View File

@ -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,16 +255,18 @@ func (err *sdkError) ABCILog() string {
func (err *sdkError) Result() Result {
return Result{
Code: err.ABCICode(),
Log: err.ABCILog(),
Code: err.Code(),
Codespace: err.Codespace(),
Log: err.ABCILog(),
}
}
// QueryResult allows us to return sdk.Error.QueryResult() in query responses
func (err *sdkError) QueryResult() abci.ResponseQuery {
return abci.ResponseQuery{
Code: uint32(err.ABCICode()),
Log: err.ABCILog(),
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"`
}

View File

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

View File

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

View File

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

View File

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

View File

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

11
types/module_clients.go Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,7 +110,20 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
if err != nil {
return err
}
fmt.Printf("%s\n", json)
if viper.GetString(flagOutfile) == "" {
fmt.Printf("%s\n", json)
return
}
fp, err := os.OpenFile(
viper.GetString(flagOutfile), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644,
)
if err != nil {
return err
}
defer fp.Close()
fmt.Fprintf(fp, "%s\n", json)
return
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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