Add first Basecoin test harness

This commit is contained in:
Jae Kwon
2018-01-26 06:54:03 -08:00
parent de5bf2ebc6
commit c6bad0b325
25 changed files with 434 additions and 401 deletions
+2
View File
@@ -6,6 +6,8 @@ build
docs/guide/*.sh
tools/bin/*
examples/build/*
examples/basecoin/glide.lock
examples/basecoin/app/data
baseapp/data/*
### Vagrant ###
+1
View File
@@ -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:
+47 -53
View File
@@ -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,
)
+13 -13
View File
@@ -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,
}
+3 -2
View File
@@ -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
+107
View File
@@ -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
}
+2
View File
@@ -2,6 +2,8 @@
*.swo
vendor
build
app/data
### Vagrant ###
.vagrant/
+4 -4
View File
@@ -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
+36
View File
@@ -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)
}
+9 -11
View File
@@ -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)
}
+1 -1
View File
@@ -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
+26
View File
@@ -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))
}
-15
View File
@@ -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))
}
+1 -1
View File
@@ -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()
+19
View File
@@ -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
}
-153
View File
@@ -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: []
+3 -4
View File
@@ -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
+6 -14
View File
@@ -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()
+7 -7
View File
@@ -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)
+63 -41
View File
@@ -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 = "<unknown>"
}
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 {
+2 -2
View File
@@ -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)
+34 -23
View File
@@ -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.
+25 -28
View File
@@ -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)
}
+4 -10
View File
@@ -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()
}
}
+19 -19
View File
@@ -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,