diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 6f99d2361d..fb952039cb 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -227,7 +227,7 @@ func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) { } return abci.ResponseCheckTx{ - Code: result.Code, + Code: uint32(result.Code), Data: result.Data, Log: result.Log, GasWanted: result.GasWanted, @@ -253,7 +253,7 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { } // After-handler hooks. - if result.Code == abci.CodeTypeOK { + if result.IsOK() { app.valUpdates = append(app.valUpdates, result.ValidatorUpdates...) } else { // Even though the Code is not OK, there will be some side @@ -263,7 +263,7 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { // Tell the blockchain engine (i.e. Tendermint). return abci.ResponseDeliverTx{ - Code: result.Code, + Code: uint32(result.Code), Data: result.Data, Log: result.Log, GasWanted: result.GasWanted, @@ -285,8 +285,14 @@ func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk } }() - // Validate the Tx.Msg. - err := tx.ValidateBasic() + // Get the Msg. + var msg = tx.GetMsg() + if msg == nil { + return sdk.ErrInternal("Tx.GetMsg() returned nil").Result() + } + + // Validate the Msg. + err := msg.ValidateBasic() if err != nil { return err.Result() } @@ -297,9 +303,6 @@ func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk // TODO: override default ante handler w/ custom ante handler. // Run the ante handler. - if ctx.IsZero() { - panic("why? before") - } newCtx, result, abort := app.defaultAnteHandler(ctx, tx) if isCheckTx || abort { return result @@ -313,9 +316,9 @@ func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk ctx = ctx.WithMultiStore(msCache) // Match and run route. - msgType := tx.Type() + msgType := msg.Type() handler := app.router.Route(msgType) - result = handler(ctx, tx) + result = handler(ctx, msg) // If result was successful, write to app.msDeliver or app.msCheck. if result.IsOK() { diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index d851a700ea..6e0f6c8e28 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -22,10 +22,11 @@ type testUpdatePowerTx struct { NewPower int64 } -const txType = "testUpdatePowerTx" +const msgType = "testUpdatePowerTx" -func (tx testUpdatePowerTx) Type() string { return txType } +func (tx testUpdatePowerTx) Type() string { return msgType } func (tx testUpdatePowerTx) Get(key interface{}) (value interface{}) { return nil } +func (tx testUpdatePowerTx) GetMsg() sdk.Msg { return tx } func (tx testUpdatePowerTx) GetSignBytes() []byte { return nil } func (tx testUpdatePowerTx) ValidateBasic() sdk.Error { return nil } func (tx testUpdatePowerTx) GetSigners() []crypto.Address { return nil } @@ -44,7 +45,7 @@ func TestBasic(t *testing.T) { }) app.SetDefaultAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return }) - app.Router().AddRoute(txType, func(ctx sdk.Context, tx sdk.Tx) sdk.Result { + app.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { // TODO return sdk.Result{} }) diff --git a/baseapp/testapp.go b/baseapp/testapp.go index 4114058f8e..c8708e222d 100644 --- a/baseapp/testapp.go +++ b/baseapp/testapp.go @@ -63,7 +63,7 @@ func (tapp *TestApp) RunCheckTx(tx sdk.Tx) sdk.Result { func (tapp *TestApp) RunDeliverTx(tx sdk.Tx) sdk.Result { tapp.ensureBeginBlock() - return tapp.BaseApp.runTx(true, nil, tx) + return tapp.BaseApp.runTx(false, nil, tx) } // NOTE: Skips authentication by wrapping msg in testTx{}. @@ -75,7 +75,7 @@ func (tapp *TestApp) RunCheckMsg(msg sdk.Msg) sdk.Result { // 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) + return tapp.RunDeliverTx(tx) } func (tapp *TestApp) CommitMultiStore() sdk.CommitMultiStore { @@ -97,6 +97,7 @@ type testTx struct { sdk.Msg } +func (tx testTx) GetMsg() sdk.Msg { return tx.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 } diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 24d71e7c22..206257d2cc 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -30,7 +30,11 @@ func TestSendMsg(t *testing.T) { }, } - // Run a SendMsg. + // Run a Check on SendMsg. res := tba.RunCheckMsg(msg) assert.Equal(t, sdk.CodeOK, res.Code, res.Log) + + // Run a Deliver on SendMsg. + res = tba.RunDeliverMsg(msg) + assert.Equal(t, sdk.CodeUnrecognizedAddress, res.Code, res.Log) } diff --git a/examples/dummy/main.go b/examples/dummy/main.go index 27abb4079e..6457fb28c9 100644 --- a/examples/dummy/main.go +++ b/examples/dummy/main.go @@ -51,10 +51,10 @@ func main() { } func DummyHandler(storeKey sdk.StoreKey) sdk.Handler { - return func(ctx sdk.Context, tx sdk.Tx) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { // tx is already unmarshalled - key := tx.Get("key").([]byte) - value := tx.Get("value").([]byte) + key := msg.Get("key").([]byte) + value := msg.Get("value").([]byte) store := ctx.KVStore(storeKey) store.Set(key, value) diff --git a/examples/dummy/tx.go b/examples/dummy/tx.go index e4206e10c2..2731686259 100644 --- a/examples/dummy/tx.go +++ b/examples/dummy/tx.go @@ -7,6 +7,7 @@ import ( crypto "github.com/tendermint/go-crypto" ) +// An sdk.Tx which is its own sdk.Msg. type dummyTx struct { key []byte value []byte @@ -30,6 +31,10 @@ func (tx dummyTx) Type() string { return "dummy" } +func (tx dummyTx) GetMsg() sdk.Msg { + return tx +} + func (tx dummyTx) GetSignBytes() []byte { return tx.bytes } diff --git a/types/errors.go b/types/errors.go index fdbf365582..3f93045f69 100644 --- a/types/errors.go +++ b/types/errors.go @@ -2,25 +2,36 @@ package types import ( "fmt" + "github.com/tendermint/go-crypto" "runtime" ) +type CodeType uint32 + +func (code CodeType) IsOK() bool { + if code == CodeOK { + return true + } else { + return false + } +} + const ( // ABCI Response Codes // Base SDK reserves 0 ~ 99. - CodeOK uint32 = 0 - CodeInternal = 1 - CodeTxParse = 2 - CodeBadNonce = 3 - CodeUnauthorized = 4 - CodeInsufficientFunds = 5 - CodeUnknownRequest = 6 - CodeUnrecognizedAddress = 7 - CodeInvalidSequence = 8 + CodeOK CodeType = 0 + CodeInternal CodeType = 1 + CodeTxParse CodeType = 2 + CodeBadNonce CodeType = 3 + CodeUnauthorized CodeType = 4 + CodeInsufficientFunds CodeType = 5 + CodeUnknownRequest CodeType = 6 + CodeUnrecognizedAddress CodeType = 7 + CodeInvalidSequence CodeType = 8 ) // NOTE: Don't stringer this, we'll put better messages in later. -func CodeToDefaultMsg(code uint32) string { +func CodeToDefaultMsg(code CodeType) string { switch code { case CodeInternal: return "Internal error" @@ -71,8 +82,8 @@ func ErrUnknownRequest(msg string) Error { return newError(CodeUnknownRequest, msg) } -func ErrUnrecognizedAddress(msg string) Error { - return newError(CodeUnrecognizedAddress, msg) +func ErrUnrecognizedAddress(addr crypto.Address) Error { + return newError(CodeUnrecognizedAddress, addr.String()) } func ErrInvalidSequence(msg string) Error { @@ -84,7 +95,7 @@ func ErrInvalidSequence(msg string) Error { type Error interface { Error() string - ABCICode() uint32 + ABCICode() CodeType ABCILog() string Trace(msg string) Error TraceCause(cause error, msg string) Error @@ -92,7 +103,7 @@ type Error interface { Result() Result } -func NewError(code uint32, msg string) Error { +func NewError(code CodeType, msg string) Error { return newError(code, msg) } @@ -107,39 +118,39 @@ func (ti traceItem) String() string { } type sdkError struct { - code uint32 - msg string - cause error - trace []traceItem + code CodeType + msg string + cause error + traces []traceItem } -func newError(code uint32, msg string) *sdkError { +func newError(code CodeType, msg string) *sdkError { // TODO capture stacktrace if ENV is set. if msg == "" { msg = CodeToDefaultMsg(code) } return &sdkError{ - code: code, - msg: msg, - cause: nil, - trace: nil, + code: code, + msg: msg, + cause: nil, + traces: nil, } } // Implements ABCIError. func (err *sdkError) Error() string { - return fmt.Sprintf("Error{%d:%s,%v,%v}", err.code, err.msg, err.cause, len(err.trace)) + return fmt.Sprintf("Error{%d:%s,%v,%v}", err.code, err.msg, err.cause, len(err.traces)) } // Implements ABCIError. -func (err *sdkError) ABCICode() uint32 { +func (err *sdkError) ABCICode() CodeType { return err.code } // Implements ABCIError. func (err *sdkError) ABCILog() string { traceLog := "" - for _, ti := range err.trace { + for _, ti := range err.traces { traceLog += ti.String() + "\n" } return fmt.Sprintf("msg: %v\ntrace:\n%v", @@ -150,7 +161,17 @@ func (err *sdkError) ABCILog() string { // Add tracing information with msg. func (err *sdkError) Trace(msg string) Error { - _, fn, line, ok := runtime.Caller(1) + return err.doTrace(msg, 2) +} + +// Add tracing information with cause and msg. +func (err *sdkError) TraceCause(cause error, msg string) Error { + err.cause = cause + return err.doTrace(msg, 2) +} + +func (err *sdkError) doTrace(msg string, n int) Error { + _, fn, line, ok := runtime.Caller(n) if !ok { if fn == "" { fn = "" @@ -161,7 +182,7 @@ func (err *sdkError) Trace(msg string) Error { } // Include file & line number & msg. // Do not include the whole stack trace. - err.trace = append(err.trace, traceItem{ + err.traces = append(err.traces, traceItem{ filename: fn, lineno: line, msg: msg, @@ -169,12 +190,6 @@ func (err *sdkError) Trace(msg string) Error { return err } -// Add tracing information with cause and msg. -func (err *sdkError) TraceCause(cause error, msg string) Error { - err.cause = cause - return err.Trace(msg) -} - func (err *sdkError) Cause() error { return err.cause } diff --git a/types/handler.go b/types/handler.go index 456da14a21..6b45f54739 100644 --- a/types/handler.go +++ b/types/handler.go @@ -1,6 +1,6 @@ package types -type Handler func(ctx Context, tx Tx) Result +type Handler func(ctx Context, msg Msg) Result // If newCtx.IsZero(), ctx is used instead. type AnteHandler func(ctx Context, tx Tx) (newCtx Context, result Result, abort bool) diff --git a/types/result.go b/types/result.go index 671cae5eae..412a9778de 100644 --- a/types/result.go +++ b/types/result.go @@ -9,7 +9,7 @@ import ( type Result struct { // Code is the response code, is stored back on the chain. - Code uint32 + Code CodeType // Data is any data returned from the app. Data []byte @@ -36,5 +36,5 @@ type Result struct { // TODO: In the future, more codes may be OK. func (res Result) IsOK() bool { - return res.Code == CodeOK + return res.Code.IsOK() } diff --git a/types/tx_msg.go b/types/tx_msg.go index 423fca73ba..8e7a8e4281 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -27,7 +27,9 @@ type Msg interface { } type Tx interface { - Msg + + // Gets the Msg. + GetMsg() Msg // The address that pays the base fee for this message. The fee is // deducted before the Msg is processed. @@ -50,6 +52,7 @@ type StdTx struct { Signatures []StdSignature } +func (tx StdTx) GetMsg() Msg { return tx.Msg } func (tx StdTx) GetFeePayer() crypto.Address { return tx.Signatures[0].PubKey.Address() } func (tx StdTx) GetSignatures() []StdSignature { return tx.Signatures } diff --git a/x/auth/ante.go b/x/auth/ante.go index fb54dee66f..a91fa55c28 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -18,7 +18,7 @@ func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler { payerAcc := accountMapper.GetAccount(ctx, payerAddr) if payerAcc == nil { return ctx, - sdk.ErrUnrecognizedAddress("").Result(), + sdk.ErrUnrecognizedAddress(payerAddr).Result(), true } // TODO: Charge fee from payerAcc. @@ -29,61 +29,66 @@ func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler { // create a Tx with no payer. } - // Ensure that signatures are correct. - var signerAddrs = tx.GetSigners() - var signerAccs = make([]sdk.Account, len(signerAddrs)) - var signatures = tx.GetSignatures() + var sigs = tx.GetSignatures() - // Assert that there are signers. - if len(signerAddrs) == 0 { - if !bam.IsTestAppTx(tx) { + // Assert that there are signatures. + if !bam.IsTestAppTx(tx) { + if len(sigs) == 0 { return ctx, sdk.ErrUnauthorized("no signers").Result(), true } } + // Ensure that sigs are correct. + var msg = tx.GetMsg() + var signerAddrs = msg.GetSigners() + var signerAccs = make([]sdk.Account, len(signerAddrs)) + // Assert that number of signatures is correct. - if len(signatures) != len(signerAddrs) { - return ctx, - sdk.ErrUnauthorized("wrong number of signers").Result(), - true - } + if !bam.IsTestAppTx(tx) { + if len(sigs) != len(signerAddrs) { + return ctx, + sdk.ErrUnauthorized("wrong number of signers").Result(), + true + } - // Check each nonce and sig. - for i, sig := range signatures { + // Check each nonce and sig. + // TODO Refactor out. + for i, sig := range sigs { - var signerAcc = accountMapper.GetAccount(ctx, signerAddrs[i]) - signerAccs[i] = signerAcc + var signerAcc = accountMapper.GetAccount(ctx, signerAddrs[i]) + signerAccs[i] = signerAcc - // If no pubkey, set pubkey. - if signerAcc.GetPubKey() == nil { - err := signerAcc.SetPubKey(sig.PubKey) - if err != nil { + // If no pubkey, set pubkey. + if signerAcc.GetPubKey() == nil { + err := signerAcc.SetPubKey(sig.PubKey) + if err != nil { + 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.ErrInternal("setting PubKey on signer").Result(), + sdk.ErrInvalidSequence("").Result(), true } - } + signerAcc.SetSequence(seq + 1) - // Check and increment sequence number. - seq := signerAcc.GetSequence() - if seq != sig.Sequence { - return ctx, - sdk.ErrInvalidSequence("").Result(), - true - } - signerAcc.SetSequence(seq + 1) + // Check sig. + if !sig.PubKey.VerifyBytes(msg.GetSignBytes(), sig.Signature) { + return ctx, + sdk.ErrUnauthorized("").Result(), + true + } - // Check sig. - if !sig.PubKey.VerifyBytes(tx.GetSignBytes(), sig.Signature) { - return ctx, - sdk.ErrUnauthorized("").Result(), - true + // Save the account. + accountMapper.SetAccount(ctx, signerAcc) } - - // Save the account. - accountMapper.SetAccount(ctx, signerAcc) } ctx = WithSigners(ctx, signerAccs) diff --git a/x/bank/errors.go b/x/bank/errors.go index a6311786c6..b922e166d4 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -5,19 +5,21 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +type CodeType = sdk.CodeType + const ( // Coin errors reserve 100 ~ 199. - CodeInvalidInput uint32 = 101 - CodeInvalidOutput uint32 = 102 - CodeInvalidAddress uint32 = 103 - CodeUnknownAddress uint32 = 104 - CodeInsufficientCoins uint32 = 105 - CodeInvalidCoins uint32 = 106 - CodeUnknownRequest uint32 = sdk.CodeUnknownRequest + CodeInvalidInput CodeType = 101 + CodeInvalidOutput CodeType = 102 + CodeInvalidAddress CodeType = 103 + CodeUnknownAddress CodeType = 104 + CodeInsufficientCoins CodeType = 105 + CodeInvalidCoins CodeType = 106 + CodeUnknownRequest CodeType = sdk.CodeUnknownRequest ) // NOTE: Don't stringer this, we'll put better messages in later. -func codeToDefaultMsg(code uint32) string { +func codeToDefaultMsg(code CodeType) string { switch code { case CodeInvalidInput: return "Invalid input coins" @@ -83,7 +85,7 @@ func ErrUnknownRequest(msg string) sdk.Error { //---------------------------------------- -func msgOrDefaultMsg(msg string, code uint32) string { +func msgOrDefaultMsg(msg string, code CodeType) string { if msg != "" { return msg } else { @@ -91,7 +93,7 @@ func msgOrDefaultMsg(msg string, code uint32) string { } } -func newError(code uint32, msg string) sdk.Error { +func newError(code CodeType, 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 9b6833ffa4..faa69df40a 100644 --- a/x/bank/handler.go +++ b/x/bank/handler.go @@ -1,23 +1,23 @@ package bank import ( - sdk "github.com/cosmos/cosmos-sdk/types" "reflect" + + sdk "github.com/cosmos/cosmos-sdk/types" ) // Handle all "bank" type messages. func NewHandler(am sdk.AccountMapper) sdk.Handler { - return func(ctx sdk.Context, tx sdk.Tx) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { cm := CoinMapper{am} - msg := tx.(sdk.Msg) switch msg := msg.(type) { case SendMsg: return handleSendMsg(ctx, cm, msg) case IssueMsg: return handleIssueMsg(ctx, cm, msg) default: - errMsg := "Unrecognized bank Tx type: " + reflect.TypeOf(tx).Name() + errMsg := "Unrecognized bank Msg type: " + reflect.TypeOf(msg).Name() return sdk.ErrUnknownRequest(errMsg).Result() } } @@ -31,14 +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 ErrInvalidInput("").TraceCause(err, "").Result() + return err.Result() } } for _, out := range msg.Outputs { _, err := cm.AddCoins(ctx, out.Address, out.Coins) if err != nil { - return ErrInvalidOutput("").TraceCause(err, "").Result() + return err.Result() } } diff --git a/x/bank/mapper.go b/x/bank/mapper.go index 5567fd8ac1..00fb4ca3b6 100644 --- a/x/bank/mapper.go +++ b/x/bank/mapper.go @@ -13,10 +13,10 @@ type CoinMapper struct { } // SubtractCoins subtracts amt from the coins at the addr. -func (cm CoinMapper) SubtractCoins(ctx sdk.Context, addr crypto.Address, amt sdk.Coins) (sdk.Coins, error) { +func (cm CoinMapper) SubtractCoins(ctx sdk.Context, addr crypto.Address, amt sdk.Coins) (sdk.Coins, sdk.Error) { acc := cm.am.GetAccount(ctx, addr) if acc == nil { - return amt, fmt.Errorf("Sending account (%s) does not exist", addr) + return amt, sdk.ErrUnrecognizedAddress(addr) } coins := acc.GetCoins() @@ -31,7 +31,7 @@ func (cm CoinMapper) SubtractCoins(ctx sdk.Context, addr crypto.Address, amt sdk } // AddCoins adds amt to the coins at the addr. -func (cm CoinMapper) AddCoins(ctx sdk.Context, addr crypto.Address, amt sdk.Coins) (sdk.Coins, error) { +func (cm CoinMapper) AddCoins(ctx sdk.Context, addr crypto.Address, amt sdk.Coins) (sdk.Coins, sdk.Error) { acc := cm.am.GetAccount(ctx, addr) if acc == nil { acc = cm.am.NewAccountWithAddress(ctx, addr)