Skip to content

Commit

Permalink
Separation of Tx from Msg; CodeType
Browse files Browse the repository at this point in the history
  • Loading branch information
jaekwon committed Jan 26, 2018
1 parent 05036e3 commit b95b67d
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 115 deletions.
23 changes: 13 additions & 10 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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()
}
Expand All @@ -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
Expand All @@ -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() {
Expand Down
7 changes: 4 additions & 3 deletions baseapp/baseapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand All @@ -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{}
})
Expand Down
5 changes: 3 additions & 2 deletions baseapp/testapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}.
Expand All @@ -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 {
Expand All @@ -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 }
Expand Down
6 changes: 5 additions & 1 deletion examples/basecoin/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
6 changes: 3 additions & 3 deletions examples/dummy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions examples/dummy/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand Down
83 changes: 49 additions & 34 deletions types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -84,15 +95,15 @@ 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
Cause() error
Result() Result
}

func NewError(code uint32, msg string) Error {
func NewError(code CodeType, msg string) Error {
return newError(code, msg)
}

Expand All @@ -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",
Expand All @@ -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 = "<unknown>"
Expand All @@ -161,20 +182,14 @@ 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,
})
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
}
Expand Down
2 changes: 1 addition & 1 deletion types/handler.go
Original file line number Diff line number Diff line change
@@ -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)
4 changes: 2 additions & 2 deletions types/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
}
5 changes: 4 additions & 1 deletion types/tx_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 }

Expand Down
Loading

0 comments on commit b95b67d

Please sign in to comment.