diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index d559340c6..6f99d2361 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -297,16 +297,31 @@ 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. - ctx, result, abort := app.defaultAnteHandler(ctx, tx) + if ctx.IsZero() { + panic("why? before") + } + newCtx, result, abort := app.defaultAnteHandler(ctx, tx) if isCheckTx || abort { return result } + if !newCtx.IsZero() { + ctx = newCtx + } + + // CacheWrap app.msDeliver in case it fails. + msCache := app.getMultiStore(isCheckTx).CacheMultiStore() + ctx = ctx.WithMultiStore(msCache) // Match and run route. msgType := tx.Type() handler := app.router.Route(msgType) result = handler(ctx, tx) + // If result was successful, write to app.msDeliver or app.msCheck. + if result.IsOK() { + msCache.Write() + } + return result } @@ -335,6 +350,14 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { //---------------------------------------- // Misc. +func (app *BaseApp) getMultiStore(isCheckTx bool) sdk.MultiStore { + if isCheckTx { + return app.msCheck + } else { + return app.msDeliver + } +} + // Return index of list with validator of same PubKey, or -1 if no match func pubKeyIndex(val *abci.Validator, list []*abci.Validator) int { for i, v := range list { diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 48105e22d..d851a700e 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -77,7 +77,7 @@ func TestBasic(t *testing.T) { } txBytes := toJSON(tx) res := app.DeliverTx(txBytes) - assert.True(t, res.IsOK(), "%#v", res) + assert.True(t, res.IsOK(), "%#v\nABCI log: %s", res, res.Log) } // Simulate the end of a block. diff --git a/types/context.go b/types/context.go index 9a5122c13..f8c8ecc7a 100644 --- a/types/context.go +++ b/types/context.go @@ -36,15 +36,19 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byt pst: newThePast(), gen: 0, } - c = c.withMultiStore(ms) - c = c.withBlockHeader(header) - c = c.withBlockHeight(header.Height) - c = c.withChainID(header.ChainID) - c = c.withIsCheckTx(isCheckTx) - c = c.withTxBytes(txBytes) + c = c.WithMultiStore(ms) + c = c.WithBlockHeader(header) + c = c.WithBlockHeight(header.Height) + c = c.WithChainID(header.ChainID) + c = c.WithIsCheckTx(isCheckTx) + c = c.WithTxBytes(txBytes) return c } +func (c Context) IsZero() bool { + return c.Context == nil +} + //---------------------------------------- // Getting a value @@ -83,10 +87,6 @@ func (c Context) WithProtoMsg(key interface{}, value proto.Message) Context { return c.withValue(key, value) } -func (c Context) WithMultiStore(key StoreKey, ms MultiStore) Context { - return c.withValue(key, ms) -} - func (c Context) WithString(key interface{}, value string) Context { return c.withValue(key, value) } @@ -156,34 +156,28 @@ func (c Context) TxBytes() []byte { return c.Value(contextKeyTxBytes).([]byte) } -// Unexposed to prevent overriding. -func (c Context) withMultiStore(ms MultiStore) Context { +func (c Context) WithMultiStore(ms MultiStore) Context { return c.withValue(contextKeyMultiStore, ms) } -// Unexposed to prevent overriding. -func (c Context) withBlockHeader(header abci.Header) Context { +func (c Context) WithBlockHeader(header abci.Header) Context { var _ proto.Message = &header // for cloning. return c.withValue(contextKeyBlockHeader, header) } -// Unexposed to prevent overriding. -func (c Context) withBlockHeight(height int64) Context { +func (c Context) WithBlockHeight(height int64) Context { return c.withValue(contextKeyBlockHeight, height) } -// Unexposed to prevent overriding. -func (c Context) withChainID(chainID string) Context { +func (c Context) WithChainID(chainID string) Context { return c.withValue(contextKeyChainID, chainID) } -// Unexposed to prevent overriding. -func (c Context) withIsCheckTx(isCheckTx bool) Context { +func (c Context) WithIsCheckTx(isCheckTx bool) Context { return c.withValue(contextKeyIsCheckTx, isCheckTx) } -// Unexposed to prevent overriding. -func (c Context) withTxBytes(txBytes []byte) Context { +func (c Context) WithTxBytes(txBytes []byte) Context { return c.withValue(contextKeyTxBytes, txBytes) } diff --git a/types/handler.go b/types/handler.go index 93b01d9d9..456da14a2 100644 --- a/types/handler.go +++ b/types/handler.go @@ -2,4 +2,5 @@ package types type Handler func(ctx Context, tx Tx) 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 3ce194c25..671cae5ea 100644 --- a/types/result.go +++ b/types/result.go @@ -33,3 +33,8 @@ type Result struct { // Tags are used for transaction indexing and pubsub. Tags []cmn.KVPair } + +// TODO: In the future, more codes may be OK. +func (res Result) IsOK() bool { + return res.Code == CodeOK +} diff --git a/x/auth/ante.go b/x/auth/ante.go index 9ea9aa107..fb54dee66 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -8,7 +8,7 @@ import ( func NewAnteHandler(accountMapper sdk.AccountMapper) sdk.AnteHandler { return func( ctx sdk.Context, tx sdk.Tx, - ) (newCtx sdk.Context, res sdk.Result, abort bool) { + ) (_ sdk.Context, _ sdk.Result, abort bool) { // Deduct the fee from the fee payer. // This is done first because it only