From c6bad0b325e683a51263e495a17413c9128ba19c Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Fri, 26 Jan 2018 04:19:33 -0800 Subject: [PATCH] Add first Basecoin test harness --- .gitignore | 2 + Makefile | 1 + baseapp/baseapp.go | 100 ++++++++-------- baseapp/baseapp_test.go | 26 ++--- baseapp/context.go | 5 +- baseapp/testapp.go | 107 +++++++++++++++++ examples/basecoin/.gitignore | 2 + examples/basecoin/app/app.go | 8 +- examples/basecoin/app/app_test.go | 36 ++++++ examples/basecoin/app/init_baseapp.go | 20 ++-- examples/basecoin/app/init_capkeys.go | 2 +- examples/basecoin/app/init_handlers.go | 26 +++++ examples/basecoin/app/init_routes.go | 15 --- examples/basecoin/app/init_stores.go | 2 +- examples/basecoin/app/testapp.go | 19 +++ examples/basecoin/glide.lock | 153 ------------------------- examples/dummy/tx.go | 7 +- store/cachemultistore.go | 20 +--- store/rootmultistore.go | 14 +-- types/errors.go | 104 ++++++++++------- types/tx_msg.go | 4 +- x/auth/ante.go | 57 +++++---- x/bank/errors.go | 53 ++++----- x/bank/handler.go | 14 +-- x/bank/tx.go | 38 +++--- 25 files changed, 434 insertions(+), 401 deletions(-) create mode 100644 baseapp/testapp.go create mode 100644 examples/basecoin/app/app_test.go create mode 100644 examples/basecoin/app/init_handlers.go delete mode 100644 examples/basecoin/app/init_routes.go create mode 100644 examples/basecoin/app/testapp.go delete mode 100644 examples/basecoin/glide.lock diff --git a/.gitignore b/.gitignore index 495d75a118..4321fb8d05 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ build docs/guide/*.sh tools/bin/* examples/build/* +examples/basecoin/glide.lock +examples/basecoin/app/data baseapp/data/* ### Vagrant ### diff --git a/Makefile b/Makefile index 4dc0c407e5..291e647f2f 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,7 @@ TUTORIALS=$(shell find docs/guide -name "*md" -type f) test: test_unit # test_cli test_unit: + @rm -rf examples/basecoin/vendor/ @go test $(PACKAGES) test_cover: diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 5c3e7b2983..d559340c62 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "os" + "runtime/debug" "github.com/golang/protobuf/proto" "github.com/pkg/errors" @@ -29,7 +30,7 @@ type BaseApp struct { db dbm.DB // Main (uncached) state - ms sdk.CommitMultiStore + cms sdk.CommitMultiStore // Unmarshal []byte into sdk.Tx txDecoder sdk.TxDecoder @@ -43,10 +44,10 @@ type BaseApp struct { //-------------------- // Volatile - // CheckTx state, a cache-wrap of `.ms`. + // CheckTx state, a cache-wrap of `.cms`. msCheck sdk.CacheMultiStore - // DeliverTx state, a cache-wrap of `.ms`. + // DeliverTx state, a cache-wrap of `.cms`. msDeliver sdk.CacheMultiStore // Current block header @@ -63,7 +64,7 @@ func NewBaseApp(name string) *BaseApp { logger: makeDefaultLogger(), name: name, db: nil, - ms: nil, + cms: nil, router: NewRouter(), } baseapp.initDB() @@ -83,8 +84,8 @@ func (app *BaseApp) initDB() { } func (app *BaseApp) initMultiStore() { - ms := store.NewCommitMultiStore(app.db) - app.ms = ms + cms := store.NewCommitMultiStore(app.db) + app.cms = cms } func (app *BaseApp) Name() string { @@ -92,37 +93,17 @@ func (app *BaseApp) Name() string { } func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) { - app.ms.MountStoreWithDB(key, typ, app.db) -} - -func (app *BaseApp) TxDecoder() sdk.TxDecoder { - return app.txDecoder + app.cms.MountStoreWithDB(key, typ, app.db) } func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) { app.txDecoder = txDecoder } -func (app *BaseApp) DefaultAnteHandler() sdk.AnteHandler { - return app.defaultAnteHandler -} - func (app *BaseApp) SetDefaultAnteHandler(ah sdk.AnteHandler) { app.defaultAnteHandler = ah } -func (app *BaseApp) MultiStore() sdk.MultiStore { - return app.ms -} - -func (app *BaseApp) MultiStoreCheck() sdk.MultiStore { - return app.msCheck -} - -func (app *BaseApp) MultiStoreDeliver() sdk.MultiStore { - return app.msDeliver -} - func (app *BaseApp) Router() Router { return app.router } @@ -134,29 +115,29 @@ func (app *BaseApp) SetInitStater(...) {} */ func (app *BaseApp) LoadLatestVersion(mainKey sdk.StoreKey) error { - app.ms.LoadLatestVersion() + app.cms.LoadLatestVersion() return app.initFromStore(mainKey) } func (app *BaseApp) LoadVersion(version int64, mainKey sdk.StoreKey) error { - app.ms.LoadVersion(version) + app.cms.LoadVersion(version) return app.initFromStore(mainKey) } // The last CommitID of the multistore. func (app *BaseApp) LastCommitID() sdk.CommitID { - return app.ms.LastCommitID() + return app.cms.LastCommitID() } // The last commited block height. func (app *BaseApp) LastBlockHeight() int64 { - return app.ms.LastCommitID().Version + return app.cms.LastCommitID().Version } -// Initializes the remaining logic from app.ms. +// Initializes the remaining logic from app.cms. func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error { - var lastCommitID = app.ms.LastCommitID() - var main = app.ms.GetKVStore(mainKey) + var lastCommitID = app.cms.LastCommitID() + var main = app.cms.GetKVStore(mainKey) var header *abci.Header // Main store should exist. @@ -196,7 +177,7 @@ func (app *BaseApp) initFromStore(mainKey sdk.StoreKey) error { // Implements ABCI. func (app *BaseApp) Info(req abci.RequestInfo) abci.ResponseInfo { - lastCommitID := app.ms.LastCommitID() + lastCommitID := app.cms.LastCommitID() return abci.ResponseInfo{ Data: app.name, @@ -227,8 +208,8 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) { // NOTE: For consistency we should unset these upon EndBlock. app.header = &req.Header - app.msDeliver = app.ms.CacheMultiStore() - app.msCheck = app.ms.CacheMultiStore() + app.msDeliver = app.cms.CacheMultiStore() + app.msCheck = app.cms.CacheMultiStore() app.valUpdates = nil return } @@ -236,7 +217,14 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg // Implements ABCI. func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) { - result := app.runTx(true, txBytes) + // Decode the Tx. + var result sdk.Result + var tx, err = app.txDecoder(txBytes) + if err != nil { + result = err.Result() + } else { + result = app.runTx(true, txBytes, tx) + } return abci.ResponseCheckTx{ Code: result.Code, @@ -255,7 +243,14 @@ func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) { // Implements ABCI. func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { - result := app.runTx(false, txBytes) + // Decode the Tx. + var result sdk.Result + var tx, err = app.txDecoder(txBytes) + if err != nil { + result = err.Result() + } else { + result = app.runTx(false, txBytes, tx) + } // After-handler hooks. if result.Code == abci.CodeTypeOK { @@ -277,29 +272,28 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { } } -func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte) (result sdk.Result) { +// txBytes may be nil in some cases, for example, when tx is +// coming from TestApp. Also, in the future we may support +// "internal" transactions. +func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk.Result) { // Handle any panics. defer func() { if r := recover(); r != nil { - result = sdk.Result{ - Code: 1, // TODO - Log: fmt.Sprintf("Recovered: %v\n", r), - } + log := fmt.Sprintf("Recovered: %v\nstack:\n%v", r, string(debug.Stack())) + result = sdk.ErrInternal(log).Result() } }() - // Construct a Context. - var ctx = app.NewContext(isCheckTx, txBytes) - - // Decode the Tx. - tx, err := app.txDecoder(txBytes) + // Validate the Tx.Msg. + err := tx.ValidateBasic() if err != nil { - return sdk.Result{ - Code: 1, // TODO - } + return err.Result() } + // Construct a Context. + var ctx = app.newContext(isCheckTx, txBytes) + // TODO: override default ante handler w/ custom ante handler. // Run the ante handler. @@ -329,7 +323,7 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc // Implements ABCI. func (app *BaseApp) Commit() (res abci.ResponseCommit) { app.msDeliver.Write() - commitID := app.ms.Commit() + commitID := app.cms.Commit() app.logger.Debug("Commit synced", "commit", commitID, ) diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index e6429a54cd..48105e22dd 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -17,28 +17,28 @@ import ( ) // A mock transaction to update a validator's voting power. -type testTx struct { +type testUpdatePowerTx struct { Addr []byte NewPower int64 } -const txType = "testTx" +const txType = "testUpdatePowerTx" -func (tx testTx) Type() string { return txType } -func (tx testTx) Get(key interface{}) (value interface{}) { return nil } -func (tx testTx) GetSignBytes() []byte { return nil } -func (tx testTx) ValidateBasic() error { return nil } -func (tx testTx) GetSigners() []crypto.Address { return nil } -func (tx testTx) GetFeePayer() crypto.Address { return nil } -func (tx testTx) GetSignatures() []sdk.StdSignature { return nil } +func (tx testUpdatePowerTx) Type() string { return txType } +func (tx testUpdatePowerTx) Get(key interface{}) (value interface{}) { return nil } +func (tx testUpdatePowerTx) GetSignBytes() []byte { return nil } +func (tx testUpdatePowerTx) ValidateBasic() sdk.Error { return nil } +func (tx testUpdatePowerTx) GetSigners() []crypto.Address { return nil } +func (tx testUpdatePowerTx) GetFeePayer() crypto.Address { return nil } +func (tx testUpdatePowerTx) GetSignatures() []sdk.StdSignature { return nil } func TestBasic(t *testing.T) { // Create app. app := NewBaseApp(t.Name()) - storeKeys := createMounts(app.ms) - app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, error) { - var ttx testTx + storeKeys := createMounts(app.cms) + app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) { + var ttx testUpdatePowerTx fromJSON(txBytes, &ttx) return ttx, nil }) @@ -71,7 +71,7 @@ func TestBasic(t *testing.T) { // Add 1 to each validator's voting power. for i, val := range valSet { - tx := testTx{ + tx := testUpdatePowerTx{ Addr: makePubKey(secret(i)).Address(), NewPower: val.Power + 1, } diff --git a/baseapp/context.go b/baseapp/context.go index fc00a27cb7..cbed01cbd5 100644 --- a/baseapp/context.go +++ b/baseapp/context.go @@ -2,9 +2,10 @@ package baseapp import sdk "github.com/cosmos/cosmos-sdk/types" -// NOTE: Unstable. // Returns a new Context suitable for AnteHandler (and indirectly Handler) processing. -func (app *BaseApp) NewContext(isCheckTx bool, txBytes []byte) sdk.Context { +// NOTE: txBytes may be nil to support TestApp.RunCheckTx +// and TestApp.RunDeliverTx. +func (app *BaseApp) newContext(isCheckTx bool, txBytes []byte) sdk.Context { var store sdk.MultiStore if isCheckTx { store = app.msCheck diff --git a/baseapp/testapp.go b/baseapp/testapp.go new file mode 100644 index 0000000000..4114058f8e --- /dev/null +++ b/baseapp/testapp.go @@ -0,0 +1,107 @@ +package baseapp + +import ( + abci "github.com/tendermint/abci/types" + "github.com/tendermint/go-crypto" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TestApp wraps BaseApp with helper methods, +// and exposes more functionality than otherwise needed. +type TestApp struct { + *BaseApp + + // These get set as we receive them. + *abci.ResponseBeginBlock + *abci.ResponseEndBlock +} + +func NewTestApp(bapp *BaseApp) *TestApp { + app := &TestApp{ + BaseApp: bapp, + } + return app +} + +func (tapp *TestApp) RunBeginBlock() { + if tapp.header != nil { + panic("TestApp.header not nil, BeginBlock already run, or EndBlock not yet run.") + } + cms := tapp.CommitMultiStore() + lastCommit := cms.LastCommitID() + header := abci.Header{ + ChainID: "chain_" + tapp.BaseApp.name, + Height: lastCommit.Version + 1, + Time: -1, // TODO + NumTxs: -1, // TODO + LastCommitHash: lastCommit.Hash, + DataHash: nil, // TODO + ValidatorsHash: nil, // TODO + AppHash: nil, // TODO + } + res := tapp.BeginBlock(abci.RequestBeginBlock{ + Hash: nil, // TODO + Header: header, + AbsentValidators: nil, // TODO + ByzantineValidators: nil, // TODO + }) + tapp.ResponseBeginBlock = &res + return +} + +func (tapp *TestApp) ensureBeginBlock() { + if tapp.header == nil { + panic("TestApp.header was nil, call TestApp.RunBeginBlock()") + } +} + +func (tapp *TestApp) RunCheckTx(tx sdk.Tx) sdk.Result { + tapp.ensureBeginBlock() + return tapp.BaseApp.runTx(true, nil, tx) +} + +func (tapp *TestApp) RunDeliverTx(tx sdk.Tx) sdk.Result { + tapp.ensureBeginBlock() + return tapp.BaseApp.runTx(true, nil, tx) +} + +// NOTE: Skips authentication by wrapping msg in testTx{}. +func (tapp *TestApp) RunCheckMsg(msg sdk.Msg) sdk.Result { + var tx = testTx{msg} + return tapp.RunCheckTx(tx) +} + +// NOTE: Skips authentication by wrapping msg in testTx{}. +func (tapp *TestApp) RunDeliverMsg(msg sdk.Msg) sdk.Result { + var tx = testTx{msg} + return tapp.RunCheckTx(tx) +} + +func (tapp *TestApp) CommitMultiStore() sdk.CommitMultiStore { + return tapp.BaseApp.cms +} + +func (tapp *TestApp) MultiStoreCheck() sdk.MultiStore { + return tapp.BaseApp.msCheck +} + +func (tapp *TestApp) MultiStoreDeliver() sdk.MultiStore { + return tapp.BaseApp.msDeliver +} + +//---------------------------------------- +// testTx + +type testTx struct { + sdk.Msg +} + +func (tx testTx) GetSigners() []crypto.Address { return nil } +func (tx testTx) GetFeePayer() crypto.Address { return nil } +func (tx testTx) GetSignatures() []sdk.StdSignature { return nil } + +func IsTestAppTx(tx sdk.Tx) bool { + _, ok := tx.(testTx) + return ok +} diff --git a/examples/basecoin/.gitignore b/examples/basecoin/.gitignore index 22facc0d51..25e54fd6bb 100644 --- a/examples/basecoin/.gitignore +++ b/examples/basecoin/.gitignore @@ -2,6 +2,8 @@ *.swo vendor build +app/data + ### Vagrant ### .vagrant/ diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index e6bafe5125..0c97abfbf2 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -31,10 +31,10 @@ func NewBasecoinApp() *BasecoinApp { // Create and configure app. var app = &BasecoinApp{} - app.initCapKeys() // ./init_capkeys.go - app.initBaseApp() // ./init_baseapp.go - app.initStores() // ./init_stores.go - app.initRoutes() // ./init_routes.go + app.initCapKeys() // ./init_capkeys.go + app.initBaseApp() // ./init_baseapp.go + app.initStores() // ./init_stores.go + app.initHandlers() // ./init_handlers.go // TODO: Load genesis // TODO: InitChain with validators diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go new file mode 100644 index 0000000000..24d71e7c22 --- /dev/null +++ b/examples/basecoin/app/app_test.go @@ -0,0 +1,36 @@ +package app + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/stretchr/testify/assert" + crypto "github.com/tendermint/go-crypto" +) + +func TestSendMsg(t *testing.T) { + tba := newTestBasecoinApp() + tba.RunBeginBlock() + + // Construct a SendMsg. + var msg = bank.SendMsg{ + Inputs: []bank.Input{ + { + Address: crypto.Address([]byte("input")), + Coins: sdk.Coins{{"atom", 10}}, + Sequence: 1, + }, + }, + Outputs: []bank.Output{ + { + Address: crypto.Address([]byte("output")), + Coins: sdk.Coins{{"atom", 10}}, + }, + }, + } + + // Run a SendMsg. + res := tba.RunCheckMsg(msg) + assert.Equal(t, sdk.CodeOK, res.Code, res.Log) +} diff --git a/examples/basecoin/app/init_baseapp.go b/examples/basecoin/app/init_baseapp.go index 6fd3fb292b..e7f9c183bd 100644 --- a/examples/basecoin/app/init_baseapp.go +++ b/examples/basecoin/app/init_baseapp.go @@ -3,26 +3,24 @@ package app import ( "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" ) -// initCapKeys, initBaseApp, initStores, initRoutes. +// initCapKeys, initBaseApp, initStores, initHandlers. func (app *BasecoinApp) initBaseApp() { app.BaseApp = baseapp.NewBaseApp(appName) app.initBaseAppTxDecoder() - app.initBaseAppAnteHandler() } func (app *BasecoinApp) initBaseAppTxDecoder() { - cdc := makeTxCodec() - app.BaseApp.SetTxDecoder(func(txBytes []byte) (sdk.Tx, error) { + var cdc = makeTxCodec() + app.BaseApp.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) { var tx = sdk.StdTx{} + // StdTx.Msg is an interface whose concrete + // types are registered in app/msgs.go. err := cdc.UnmarshalBinary(txBytes, &tx) - return tx, err + if err != nil { + return nil, sdk.ErrTxParse("").TraceCause(err, "") + } + return tx, nil }) } - -func (app *BasecoinApp) initBaseAppAnteHandler() { - var authAnteHandler = auth.NewAnteHandler(app.accountMapper) - app.BaseApp.SetDefaultAnteHandler(authAnteHandler) -} diff --git a/examples/basecoin/app/init_capkeys.go b/examples/basecoin/app/init_capkeys.go index 221565011e..7327c61843 100644 --- a/examples/basecoin/app/init_capkeys.go +++ b/examples/basecoin/app/init_capkeys.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// initCapKeys, initBaseApp, initStores, initRoutes. +// initCapKeys, initBaseApp, initStores, initHandlers. func (app *BasecoinApp) initCapKeys() { // All top-level capabilities keys diff --git a/examples/basecoin/app/init_handlers.go b/examples/basecoin/app/init_handlers.go new file mode 100644 index 0000000000..e19b1298d4 --- /dev/null +++ b/examples/basecoin/app/init_handlers.go @@ -0,0 +1,26 @@ +package app + +import ( + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" +) + +// initCapKeys, initBaseApp, initStores, initHandlers. +func (app *BasecoinApp) initHandlers() { + app.initDefaultAnteHandler() + app.initRouterHandlers() +} + +func (app *BasecoinApp) initDefaultAnteHandler() { + var authAnteHandler = auth.NewAnteHandler(app.accountMapper) + app.BaseApp.SetDefaultAnteHandler(authAnteHandler) +} + +func (app *BasecoinApp) initRouterHandlers() { + var router = app.BaseApp.Router() + var accountMapper = app.accountMapper + + // All handlers must be added here. + // The order matters. + router.AddRoute("bank", bank.NewHandler(accountMapper)) +} diff --git a/examples/basecoin/app/init_routes.go b/examples/basecoin/app/init_routes.go deleted file mode 100644 index 1e8e0a4272..0000000000 --- a/examples/basecoin/app/init_routes.go +++ /dev/null @@ -1,15 +0,0 @@ -package app - -import ( - "github.com/cosmos/cosmos-sdk/x/bank" -) - -// initCapKeys, initBaseApp, initStores, initRoutes. -func (app *BasecoinApp) initRoutes() { - var router = app.BaseApp.Router() - var accountMapper = app.accountMapper - - // All handlers must be added here. - // The order matters. - router.AddRoute("bank", bank.NewHandler(accountMapper)) -} diff --git a/examples/basecoin/app/init_stores.go b/examples/basecoin/app/init_stores.go index dbd1d2538b..e819ecd2c5 100644 --- a/examples/basecoin/app/init_stores.go +++ b/examples/basecoin/app/init_stores.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" ) -// initCapKeys, initBaseApp, initStores, initRoutes. +// initCapKeys, initBaseApp, initStores, initHandlers. func (app *BasecoinApp) initStores() { app.mountStores() app.initAccountMapper() diff --git a/examples/basecoin/app/testapp.go b/examples/basecoin/app/testapp.go new file mode 100644 index 0000000000..544c48c0f7 --- /dev/null +++ b/examples/basecoin/app/testapp.go @@ -0,0 +1,19 @@ +package app + +import ( + bam "github.com/cosmos/cosmos-sdk/baseapp" +) + +type testBasecoinApp struct { + *BasecoinApp + *bam.TestApp +} + +func newTestBasecoinApp() *testBasecoinApp { + app := NewBasecoinApp() + tba := &testBasecoinApp{ + BasecoinApp: app, + } + tba.TestApp = bam.NewTestApp(app.BaseApp) + return tba +} diff --git a/examples/basecoin/glide.lock b/examples/basecoin/glide.lock deleted file mode 100644 index 3b4115908a..0000000000 --- a/examples/basecoin/glide.lock +++ /dev/null @@ -1,153 +0,0 @@ -hash: 80794a3459988a7eb794baf7688c71dad4f6c26653d7b707ac0ada93f21e0776 -updated: 2018-01-23T19:03:56.956668196-08:00 -imports: -- name: github.com/btcsuite/btcd - version: 2e60448ffcc6bf78332d1fe590260095f554dd78 - subpackages: - - btcec -- name: github.com/cosmos/cosmos-sdk - version: 8650fd70c92686a192585e95413915b4302156b7 - subpackages: - - baseapp - - examples/basecoin/types - - store - - types - - x/auth - - x/bank -- name: github.com/davecgh/go-spew - version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9 - subpackages: - - spew -- name: github.com/go-kit/kit - version: e2b298466b32c7cd5579a9b9b07e968fc9d9452c - subpackages: - - log - - log/level - - log/term -- name: github.com/go-logfmt/logfmt - version: 390ab7935ee28ec6b286364bba9b4dd6410cb3d5 -- name: github.com/go-stack/stack - version: 817915b46b97fd7bb80e8ab6b69f01a53ac3eebf -- name: github.com/gogo/protobuf - version: 342cbe0a04158f6dcb03ca0079991a51a4248c02 - subpackages: - - gogoproto - - jsonpb - - proto - - protoc-gen-gogo/descriptor - - sortkeys - - types -- name: github.com/golang/protobuf - version: 1e59b77b52bf8e4b449a57e6f79f21226d571845 - subpackages: - - proto - - ptypes - - ptypes/any - - ptypes/duration - - ptypes/timestamp -- name: github.com/golang/snappy - version: 553a641470496b2327abcac10b36396bd98e45c9 -- name: github.com/jmhodges/levigo - version: c42d9e0ca023e2198120196f842701bb4c55d7b9 -- name: github.com/kr/logfmt - version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 -- name: github.com/pkg/errors - version: 645ef00459ed84a119197bfb8d8205042c6df63d -- name: github.com/rigelrozanski/common - version: f691f115798593d783b9999b1263c2f4ffecc439 -- name: github.com/syndtr/goleveldb - version: b89cc31ef7977104127d34c1bd31ebd1a9db2199 - subpackages: - - leveldb - - leveldb/cache - - leveldb/comparer - - leveldb/errors - - leveldb/filter - - leveldb/iterator - - leveldb/journal - - leveldb/memdb - - leveldb/opt - - leveldb/storage - - leveldb/table - - leveldb/util -- name: github.com/tendermint/abci - version: 4243954d8d940f9ee0646a83d48ea7a1a907529e - subpackages: - - server - - types -- name: github.com/tendermint/ed25519 - version: d8387025d2b9d158cf4efb07e7ebf814bcce2057 - subpackages: - - edwards25519 - - extra25519 -- name: github.com/tendermint/go-crypto - version: 12142af1cb4e3479ea4ac98a3171debff87519c6 - subpackages: - - keys -- name: github.com/tendermint/go-wire - version: c7801c1586f51bb28028cd420c599516d7ac9c36 - subpackages: - - data -- name: github.com/tendermint/iavl - version: ae2ea4a62f60c72dae81ca6642944ca28cf59889 -- name: github.com/tendermint/tmlibs - version: 80029abc6e20f85079cd751e659a05508773288c - subpackages: - - cli - - cli/flags - - common - - db - - events - - log - - logger - - merkle -- name: golang.org/x/crypto - version: edd5e9b0879d13ee6970a50153d85b8fec9f7686 - subpackages: - - nacl/secretbox - - openpgp/armor - - openpgp/errors - - poly1305 - - ripemd160 - - salsa20/salsa -- name: golang.org/x/net - version: 5ccada7d0a7ba9aeb5d3aca8d3501b4c2a509fec - subpackages: - - context - - http2 - - http2/hpack - - idna - - internal/timeseries - - lex/httplex - - trace -- name: golang.org/x/text - version: c01e4764d870b77f8abe5096ee19ad20d80e8075 - subpackages: - - secure/bidirule - - transform - - unicode/bidi - - unicode/norm -- name: google.golang.org/genproto - version: a8101f21cf983e773d0c1133ebc5424792003214 - subpackages: - - googleapis/rpc/status -- name: google.golang.org/grpc - version: 401e0e00e4bb830a10496d64cd95e068c5bf50de - subpackages: - - balancer - - codes - - connectivity - - credentials - - grpclb/grpc_lb_v1/messages - - grpclog - - internal - - keepalive - - metadata - - naming - - peer - - resolver - - stats - - status - - tap - - transport -testImports: [] diff --git a/examples/dummy/tx.go b/examples/dummy/tx.go index 63343abc6e..e4206e10c2 100644 --- a/examples/dummy/tx.go +++ b/examples/dummy/tx.go @@ -2,7 +2,6 @@ package main import ( "bytes" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" crypto "github.com/tendermint/go-crypto" @@ -36,7 +35,7 @@ func (tx dummyTx) GetSignBytes() []byte { } // Should the app be calling this? Or only handlers? -func (tx dummyTx) ValidateBasic() error { +func (tx dummyTx) ValidateBasic() sdk.Error { return nil } @@ -52,7 +51,7 @@ func (tx dummyTx) GetFeePayer() crypto.Address { return nil } -func decodeTx(txBytes []byte) (sdk.Tx, error) { +func decodeTx(txBytes []byte) (sdk.Tx, sdk.Error) { var tx sdk.Tx split := bytes.Split(txBytes, []byte("=")) @@ -63,7 +62,7 @@ func decodeTx(txBytes []byte) (sdk.Tx, error) { k, v := split[0], split[1] tx = dummyTx{k, v, txBytes} } else { - return nil, fmt.Errorf("too many =") + return nil, sdk.ErrTxParse("too many =") } return tx, nil diff --git a/store/cachemultistore.go b/store/cachemultistore.go index 176f8dbbfe..b53899b3d5 100644 --- a/store/cachemultistore.go +++ b/store/cachemultistore.go @@ -10,16 +10,14 @@ import ( // cacheMultiStore holds many cache-wrapped stores. // Implements MultiStore. type cacheMultiStore struct { - db CacheKVStore - lastCommitID CommitID - stores map[StoreKey]CacheWrap + db CacheKVStore + stores map[StoreKey]CacheWrap } func newCacheMultiStoreFromRMS(rms *rootMultiStore) cacheMultiStore { cms := cacheMultiStore{ - db: NewCacheKVStore(dbStoreAdapter{rms.db}), - lastCommitID: rms.lastCommitID, - stores: make(map[StoreKey]CacheWrap, len(rms.stores)), + db: NewCacheKVStore(dbStoreAdapter{rms.db}), + stores: make(map[StoreKey]CacheWrap, len(rms.stores)), } for key, store := range rms.stores { cms.stores[key] = store.CacheWrap() @@ -29,9 +27,8 @@ func newCacheMultiStoreFromRMS(rms *rootMultiStore) cacheMultiStore { func newCacheMultiStoreFromCMS(cms cacheMultiStore) cacheMultiStore { cms2 := cacheMultiStore{ - db: NewCacheKVStore(cms.db), - lastCommitID: cms.lastCommitID, - stores: make(map[StoreKey]CacheWrap, len(cms.stores)), + db: NewCacheKVStore(cms.db), + stores: make(map[StoreKey]CacheWrap, len(cms.stores)), } for key, store := range cms.stores { cms2.stores[key] = store.CacheWrap() @@ -44,11 +41,6 @@ func (cms cacheMultiStore) GetStoreType() StoreType { return sdk.StoreTypeMulti } -// Implements MultiStore. -func (cms cacheMultiStore) LastCommitID() CommitID { - return cms.lastCommitID -} - // Implements CacheMultiStore. func (cms cacheMultiStore) Write() { cms.db.Write() diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 67582d331c..f964a1fd5b 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -119,7 +119,12 @@ func (rs *rootMultiStore) LoadVersion(ver int64) error { //---------------------------------------- // +CommitStore -// Implements CommitStore. +// Implements Committer/CommitStore. +func (rs *rootMultiStore) LastCommitID() CommitID { + return rs.lastCommitID +} + +// Implements Committer/CommitStore. func (rs *rootMultiStore) Commit() CommitID { // Commit stores. @@ -141,7 +146,7 @@ func (rs *rootMultiStore) Commit() CommitID { return commitID } -// Implements CommitStore. +// Implements CacheWrapper/Store/CommitStore. func (rs *rootMultiStore) CacheWrap() CacheWrap { return rs.CacheMultiStore().(CacheWrap) } @@ -149,11 +154,6 @@ func (rs *rootMultiStore) CacheWrap() CacheWrap { //---------------------------------------- // +MultiStore -// Implements MultiStore. -func (rs *rootMultiStore) LastCommitID() CommitID { - return rs.lastCommitID -} - // Implements MultiStore. func (rs *rootMultiStore) CacheMultiStore() CacheMultiStore { return newCacheMultiStoreFromRMS(rs) diff --git a/types/errors.go b/types/errors.go index a468bac47d..fdbf365582 100644 --- a/types/errors.go +++ b/types/errors.go @@ -2,26 +2,29 @@ package types import ( "fmt" + "runtime" ) const ( // ABCI Response Codes // Base SDK reserves 0 ~ 99. - CodeInternalError uint32 = 1 - CodeTxParseError = 2 + CodeOK uint32 = 0 + CodeInternal = 1 + CodeTxParse = 2 CodeBadNonce = 3 CodeUnauthorized = 4 CodeInsufficientFunds = 5 CodeUnknownRequest = 6 CodeUnrecognizedAddress = 7 + CodeInvalidSequence = 8 ) // NOTE: Don't stringer this, we'll put better messages in later. -func CodeToDefaultLog(code uint32) string { +func CodeToDefaultMsg(code uint32) string { switch code { - case CodeInternalError: + case CodeInternal: return "Internal error" - case CodeTxParseError: + case CodeTxParse: return "Tx parse error" case CodeBadNonce: return "Bad nonce" @@ -33,6 +36,8 @@ func CodeToDefaultLog(code uint32) string { return "Unknown request" case CodeUnrecognizedAddress: return "Unrecognized address" + case CodeInvalidSequence: + return "Invalid sequence" default: return fmt.Sprintf("Unknown code %d", code) } @@ -42,32 +47,36 @@ func CodeToDefaultLog(code uint32) string { // All errors are created via constructors so as to enable us to hijack them // and inject stack traces if we really want to. -func ErrInternal(log string) Error { - return newError(CodeInternalError, log) +func ErrInternal(msg string) Error { + return newError(CodeInternal, msg) } -func ErrTxParse(log string) Error { - return newError(CodeTxParseError, log) +func ErrTxParse(msg string) Error { + return newError(CodeTxParse, msg) } -func ErrBadNonce(log string) Error { - return newError(CodeBadNonce, log) +func ErrBadNonce(msg string) Error { + return newError(CodeBadNonce, msg) } -func ErrUnauthorized(log string) Error { - return newError(CodeUnauthorized, log) +func ErrUnauthorized(msg string) Error { + return newError(CodeUnauthorized, msg) } -func ErrInsufficientFunds(log string) Error { - return newError(CodeInsufficientFunds, log) +func ErrInsufficientFunds(msg string) Error { + return newError(CodeInsufficientFunds, msg) } -func ErrUnknownRequest(log string) Error { - return newError(CodeUnknownRequest, log) +func ErrUnknownRequest(msg string) Error { + return newError(CodeUnknownRequest, msg) } -func ErrUnrecognizedAddress(log string) Error { - return newError(CodeUnrecognizedAddress, log) +func ErrUnrecognizedAddress(msg string) Error { + return newError(CodeUnrecognizedAddress, msg) +} + +func ErrInvalidSequence(msg string) Error { + return newError(CodeInvalidSequence, msg) } //---------------------------------------- @@ -83,8 +92,8 @@ type Error interface { Result() Result } -func NewError(code uint32, log string) Error { - return newError(code, log) +func NewError(code uint32, msg string) Error { + return newError(code, msg) } type traceItem struct { @@ -93,21 +102,25 @@ type traceItem struct { lineno int } +func (ti traceItem) String() string { + return fmt.Sprintf("%v:%v %v", ti.filename, ti.lineno, ti.msg) +} + type sdkError struct { code uint32 - log string + msg string cause error trace []traceItem } -func newError(code uint32, log string) *sdkError { +func newError(code uint32, msg string) *sdkError { // TODO capture stacktrace if ENV is set. - if log == "" { - log = CodeToDefaultLog(code) + if msg == "" { + msg = CodeToDefaultMsg(code) } return &sdkError{ code: code, - log: log, + msg: msg, cause: nil, trace: nil, } @@ -115,7 +128,7 @@ func newError(code uint32, log string) *sdkError { // Implements ABCIError. func (err *sdkError) Error() string { - return fmt.Sprintf("Error{%d:%s,%v,%v}", err.code, err.log, err.cause, len(err.trace)) + return fmt.Sprintf("Error{%d:%s,%v,%v}", err.code, err.msg, err.cause, len(err.trace)) } // Implements ABCIError. @@ -125,32 +138,41 @@ func (err *sdkError) ABCICode() uint32 { // Implements ABCIError. func (err *sdkError) ABCILog() string { - return err.log + traceLog := "" + for _, ti := range err.trace { + traceLog += ti.String() + "\n" + } + return fmt.Sprintf("msg: %v\ntrace:\n%v", + err.msg, + traceLog, + ) } -// Add tracing information to log with msg. +// Add tracing information with msg. func (err *sdkError) Trace(msg string) Error { - // Include file & line number & msg to log. + _, fn, line, ok := runtime.Caller(1) + if !ok { + if fn == "" { + fn = "" + } + if line <= 0 { + line = -1 + } + } + // Include file & line number & msg. // Do not include the whole stack trace. err.trace = append(err.trace, traceItem{ - filename: "todo", // TODO - lineno: -1, // TODO + filename: fn, + lineno: line, msg: msg, }) return err } -// Add tracing information to log with cause and msg. +// Add tracing information with cause and msg. func (err *sdkError) TraceCause(cause error, msg string) Error { err.cause = cause - // Include file & line number & cause & msg to log. - // Do not include the whole stack trace. - err.trace = append(err.trace, traceItem{ - filename: "todo", // TODO - lineno: -1, // TODO - msg: msg, - }) - return err + return err.Trace(msg) } func (err *sdkError) Cause() error { diff --git a/types/tx_msg.go b/types/tx_msg.go index 1782e348b0..423fca73ba 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -18,7 +18,7 @@ type Msg interface { // ValidateBasic does a simple validation check that // doesn't require access to any other information. - ValidateBasic() error + ValidateBasic() Error // Signers returns the addrs of signers that must sign. // CONTRACT: All signatures must be present to be valid. @@ -53,4 +53,4 @@ type StdTx struct { func (tx StdTx) GetFeePayer() crypto.Address { return tx.Signatures[0].PubKey.Address() } func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } -type TxDecoder func(txBytes []byte) (Tx, error) +type TxDecoder func(txBytes []byte) (Tx, Error) diff --git a/x/auth/ante.go b/x/auth/ante.go index c84394138e..9ea9aa1071 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -1,6 +1,7 @@ package auth import ( + bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,30 +14,40 @@ func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler { // This is done first because it only // requires fetching 1 account. payerAddr := tx.GetFeePayer() - payerAcc := accountMapper.GetAccount(ctx, payerAddr) - if payerAcc == nil { - return ctx, sdk.Result{ - Code: 1, // TODO - }, true + if payerAddr != nil { + payerAcc := accountMapper.GetAccount(ctx, payerAddr) + if payerAcc == nil { + return ctx, + sdk.ErrUnrecognizedAddress("").Result(), + true + } + // TODO: Charge fee from payerAcc. + // TODO: accountMapper.SetAccount(ctx, payerAddr) + } else { + // TODO: Ensure that some other spam prevention is used. + // NOTE: bam.TestApp.RunDeliverMsg/RunCheckMsg will + // create a Tx with no payer. } - // payerAcc.Subtract ? - // Ensure that signatures are correct. var signerAddrs = tx.GetSigners() var signerAccs = make([]sdk.Account, len(signerAddrs)) var signatures = tx.GetSignatures() // Assert that there are signers. - if len(signatures) == 0 { - return ctx, sdk.Result{ - Code: 1, // TODO - }, true + if len(signerAddrs) == 0 { + if !bam.IsTestAppTx(tx) { + return ctx, + sdk.ErrUnauthorized("no signers").Result(), + true + } } + + // Assert that number of signatures is correct. if len(signatures) != len(signerAddrs) { - return ctx, sdk.Result{ - Code: 1, // TODO - }, true + return ctx, + sdk.ErrUnauthorized("wrong number of signers").Result(), + true } // Check each nonce and sig. @@ -49,26 +60,26 @@ func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler { if signerAcc.GetPubKey() == nil { err := signerAcc.SetPubKey(sig.PubKey) if err != nil { - return ctx, sdk.Result{ - Code: 1, // TODO - }, true + return ctx, + sdk.ErrInternal("setting PubKey on signer").Result(), + true } } // Check and increment sequence number. seq := signerAcc.GetSequence() if seq != sig.Sequence { - return ctx, sdk.Result{ - Code: 1, // TODO - }, true + return ctx, + sdk.ErrInvalidSequence("").Result(), + true } signerAcc.SetSequence(seq + 1) // Check sig. if !sig.PubKey.VerifyBytes(tx.GetSignBytes(), sig.Signature) { - return ctx, sdk.Result{ - Code: 1, // TODO - }, true + return ctx, + sdk.ErrUnauthorized("").Result(), + true } // Save the account. diff --git a/x/bank/errors.go b/x/bank/errors.go index 327ca6a0d3..a6311786c6 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -13,12 +13,11 @@ const ( CodeUnknownAddress uint32 = 104 CodeInsufficientCoins uint32 = 105 CodeInvalidCoins uint32 = 106 - CodeInvalidSequence uint32 = 107 CodeUnknownRequest uint32 = sdk.CodeUnknownRequest ) // NOTE: Don't stringer this, we'll put better messages in later. -func codeToDefaultLog(code uint32) string { +func codeToDefaultMsg(code uint32) string { switch code { case CodeInvalidInput: return "Invalid input coins" @@ -32,69 +31,67 @@ func codeToDefaultLog(code uint32) string { return "Insufficient coins" case CodeInvalidCoins: return "Invalid coins" - case CodeInvalidSequence: - return "Invalid sequence" case CodeUnknownRequest: return "Unknown request" default: - return sdk.CodeToDefaultLog(code) + return sdk.CodeToDefaultMsg(code) } } //---------------------------------------- // Error constructors -func ErrInvalidInput(log string) sdk.Error { - return newError(CodeInvalidInput, log) +func ErrInvalidInput(msg string) sdk.Error { + return newError(CodeInvalidInput, msg) } func ErrNoInputs() sdk.Error { return newError(CodeInvalidInput, "") } -func ErrInvalidOutput(log string) sdk.Error { - return newError(CodeInvalidOutput, log) +func ErrInvalidOutput(msg string) sdk.Error { + return newError(CodeInvalidOutput, msg) } func ErrNoOutputs() sdk.Error { return newError(CodeInvalidOutput, "") } -func ErrInvalidSequence(seq int64) sdk.Error { - return newError(CodeInvalidSequence, "") +func ErrInvalidSequence(msg string) sdk.Error { + return sdk.ErrInvalidSequence(msg) } -func ErrInvalidAddress(log string) sdk.Error { - return newError(CodeInvalidAddress, log) +func ErrInvalidAddress(msg string) sdk.Error { + return newError(CodeInvalidAddress, msg) } -func ErrUnknownAddress(log string) sdk.Error { - return newError(CodeUnknownAddress, log) +func ErrUnknownAddress(msg string) sdk.Error { + return newError(CodeUnknownAddress, msg) } -func ErrInsufficientCoins(log string) sdk.Error { - return newError(CodeInsufficientCoins, log) +func ErrInsufficientCoins(msg string) sdk.Error { + return newError(CodeInsufficientCoins, msg) } -func ErrInvalidCoins(log string) sdk.Error { - return newError(CodeInvalidCoins, log) +func ErrInvalidCoins(msg string) sdk.Error { + return newError(CodeInvalidCoins, msg) } -func ErrUnknownRequest(log string) sdk.Error { - return newError(CodeUnknownRequest, log) +func ErrUnknownRequest(msg string) sdk.Error { + return newError(CodeUnknownRequest, msg) } //---------------------------------------- -func logOrDefaultLog(log string, code uint32) string { - if log != "" { - return log +func msgOrDefaultMsg(msg string, code uint32) string { + if msg != "" { + return msg } else { - return codeToDefaultLog(code) + return codeToDefaultMsg(code) } } -func newError(code uint32, log string) sdk.Error { - log = logOrDefaultLog(log, code) - return sdk.NewError(code, log) +func newError(code uint32, msg string) sdk.Error { + msg = msgOrDefaultMsg(msg, code) + return sdk.NewError(code, msg) } diff --git a/x/bank/handler.go b/x/bank/handler.go index 10c4520dea..9b6833ffa4 100644 --- a/x/bank/handler.go +++ b/x/bank/handler.go @@ -17,10 +17,8 @@ func NewHandler(am sdk.AccountMapper) sdk.Handler { case IssueMsg: return handleIssueMsg(ctx, cm, msg) default: - return sdk.Result{ - Code: 1, // TODO - Log: "Unrecognized bank Tx type: " + reflect.TypeOf(tx).Name(), - } + errMsg := "Unrecognized bank Tx type: " + reflect.TypeOf(tx).Name() + return sdk.ErrUnknownRequest(errMsg).Result() } } @@ -33,18 +31,14 @@ func handleSendMsg(ctx sdk.Context, cm CoinMapper, msg SendMsg) sdk.Result { for _, in := range msg.Inputs { _, err := cm.SubtractCoins(ctx, in.Address, in.Coins) if err != nil { - return sdk.Result{ - Code: 1, // TODO - } + return ErrInvalidInput("").TraceCause(err, "").Result() } } for _, out := range msg.Outputs { _, err := cm.AddCoins(ctx, out.Address, out.Coins) if err != nil { - return sdk.Result{ - Code: 1, // TODO - } + return ErrInvalidOutput("").TraceCause(err, "").Result() } } diff --git a/x/bank/tx.go b/x/bank/tx.go index eed7f57e70..b28fdf9c9a 100644 --- a/x/bank/tx.go +++ b/x/bank/tx.go @@ -6,7 +6,7 @@ import ( crypto "github.com/tendermint/go-crypto" - "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) // SendMsg - high level transaction of the coin module @@ -24,32 +24,32 @@ func NewSendMsg(in []Input, out []Output) SendMsg { func (msg SendMsg) Type() string { return "bank" } // TODO: "bank/send" // Implements Msg. -func (msg SendMsg) ValidateBasic() error { +func (msg SendMsg) ValidateBasic() sdk.Error { // this just makes sure all the inputs and outputs are properly formatted, // not that they actually have the money inside if len(msg.Inputs) == 0 { - return ErrNoInputs() + return ErrNoInputs().Trace("") } if len(msg.Outputs) == 0 { - return ErrNoOutputs() + return ErrNoOutputs().Trace("") } // make sure all inputs and outputs are individually valid - var totalIn, totalOut types.Coins + var totalIn, totalOut sdk.Coins for _, in := range msg.Inputs { if err := in.ValidateBasic(); err != nil { - return err + return err.Trace("") } totalIn = totalIn.Plus(in.Coins) } for _, out := range msg.Outputs { if err := out.ValidateBasic(); err != nil { - return err + return err.Trace("") } totalOut = totalOut.Plus(out.Coins) } // make sure inputs and outputs match if !totalIn.IsEqual(totalOut) { - return ErrInvalidCoins(totalIn.String()) // TODO + return ErrInvalidCoins(totalIn.String()).Trace("inputs and outputs don't match") } return nil } @@ -99,14 +99,14 @@ func NewIssueMsg(banker crypto.Address, out []Output) IssueMsg { func (msg IssueMsg) Type() string { return "bank" } // TODO: "bank/send" // Implements Msg. -func (msg IssueMsg) ValidateBasic() error { +func (msg IssueMsg) ValidateBasic() sdk.Error { // XXX if len(msg.Outputs) == 0 { - return ErrNoOutputs() + return ErrNoOutputs().Trace("") } for _, out := range msg.Outputs { if err := out.ValidateBasic(); err != nil { - return err + return err.Trace("") } } return nil @@ -140,19 +140,19 @@ func (msg IssueMsg) GetSigners() []crypto.Address { type Input struct { Address crypto.Address `json:"address"` - Coins types.Coins `json:"coins"` + Coins sdk.Coins `json:"coins"` Sequence int64 `json:"sequence"` signature crypto.Signature } // ValidateBasic - validate transaction input -func (in Input) ValidateBasic() error { +func (in Input) ValidateBasic() sdk.Error { if len(in.Address) == 0 { return ErrInvalidAddress(in.Address.String()) } if in.Sequence < 0 { - return ErrInvalidSequence(in.Sequence) + return ErrInvalidSequence("negative sequence") } if !in.Coins.IsValid() { return ErrInvalidCoins(in.Coins.String()) @@ -168,7 +168,7 @@ func (in Input) String() string { } // NewInput - create a transaction input, used with SendMsg -func NewInput(addr crypto.Address, coins types.Coins) Input { +func NewInput(addr crypto.Address, coins sdk.Coins) Input { input := Input{ Address: addr, Coins: coins, @@ -177,7 +177,7 @@ func NewInput(addr crypto.Address, coins types.Coins) Input { } // NewInputWithSequence - create a transaction input, used with SendMsg -func NewInputWithSequence(addr crypto.Address, coins types.Coins, seq int64) Input { +func NewInputWithSequence(addr crypto.Address, coins sdk.Coins, seq int64) Input { input := NewInput(addr, coins) input.Sequence = seq return input @@ -188,11 +188,11 @@ func NewInputWithSequence(addr crypto.Address, coins types.Coins, seq int64) Inp type Output struct { Address crypto.Address `json:"address"` - Coins types.Coins `json:"coins"` + Coins sdk.Coins `json:"coins"` } // ValidateBasic - validate transaction output -func (out Output) ValidateBasic() error { +func (out Output) ValidateBasic() sdk.Error { if len(out.Address) == 0 { return ErrInvalidAddress(out.Address.String()) } @@ -210,7 +210,7 @@ func (out Output) String() string { } // NewOutput - create a transaction output, used with SendMsg -func NewOutput(addr crypto.Address, coins types.Coins) Output { +func NewOutput(addr crypto.Address, coins sdk.Coins) Output { output := Output{ Address: addr, Coins: coins,