Merge pull request #1663 from cosmos/aditya/cleanup

BaseApp cleanup
This commit is contained in:
Rigel 2018-07-23 14:14:19 -04:00 committed by GitHub
commit fae728f35a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 151 additions and 119 deletions

View File

@ -4,6 +4,8 @@ BREAKING CHANGES
* [baseapp] Msgs are no longer run on CheckTx, removed `ctx.IsCheckTx()`
* [x/gov] CLI flag changed from `proposalID` to `proposal-id`
* [x/stake] Fixed the period check for the inflation calculation
* [baseapp] NewBaseApp constructor now takes sdk.TxDecoder as argument instead of wire.Codec
* [x/auth] Default TxDecoder can be found in `x/auth` rather than baseapp
* \#1606 The following CLI commands have been switched to use `--from`
* `gaiacli stake create-validator --address-validator`
* `gaiacli stake edit-validator --address-validator`
@ -32,6 +34,7 @@ IMPROVEMENTS
* [baseapp] Allow any alphanumeric character in route
* [cli] Improve error messages for all txs when the account doesn't exist
* [tools] Remove `rm -rf vendor/` from `make get_vendor_deps`
* [x/auth] Recover ErrorOutOfGas panic in order to set sdk.Result attributes correctly
* [x/stake] Add revoked to human-readable validator
* [x/gov] Votes on a proposal can now be queried
* [x/bank] Unit tests are now table-driven

View File

@ -18,7 +18,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// Key to store the header in the DB itself.
@ -44,14 +43,12 @@ type BaseApp struct {
// initialized on creation
Logger log.Logger
name string // application name from abci.Info
cdc *wire.Codec // Amino codec
db dbm.DB // common DB backend
cms sdk.CommitMultiStore // Main (uncached) state
router Router // handle any kind of message
codespacer *sdk.Codespacer // handle module codespacing
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
// must be set
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
anteHandler sdk.AnteHandler // ante handler for fee and auth
// may be nil
@ -80,17 +77,17 @@ var _ abci.Application = (*BaseApp)(nil)
// (e.g. functional options).
//
// NOTE: The db is used to store the version number for now.
// Accepts a user-defined txDecoder
// Accepts variable number of option functions, which act on the BaseApp to set configuration choices
func NewBaseApp(name string, cdc *wire.Codec, logger log.Logger, db dbm.DB, options ...func(*BaseApp)) *BaseApp {
func NewBaseApp(name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp)) *BaseApp {
app := &BaseApp{
Logger: logger,
name: name,
cdc: cdc,
db: db,
cms: store.NewCommitMultiStore(db),
router: NewRouter(),
codespacer: sdk.NewCodespacer(),
txDecoder: defaultTxDecoder(cdc),
txDecoder: txDecoder,
}
// Register the undefined & root codespaces, which should not be used by
@ -135,35 +132,6 @@ func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) {
app.cms.MountStoreWithDB(key, typ, nil)
}
// Set the txDecoder function
func (app *BaseApp) SetTxDecoder(txDecoder sdk.TxDecoder) {
app.txDecoder = txDecoder
}
// default custom logic for transaction decoding
// TODO: remove auth and wire dependencies from baseapp
// - move this to auth.DefaultTxDecoder
// - set the default here to JSON decode like docs/examples/app1 (it will fail
// for multiple messages ;))
// - pass a TxDecoder into NewBaseApp, instead of a codec.
func defaultTxDecoder(cdc *wire.Codec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx = auth.StdTx{}
if len(txBytes) == 0 {
return nil, sdk.ErrTxDecode("txBytes are empty")
}
// StdTx.Msg is an interface. The concrete types
// are registered by MakeTxCodec
err := cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode("").TraceSDK(err.Error())
}
return tx, nil
}
}
// nolint - Set functions
func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
app.initChainer = initChainer
@ -364,7 +332,9 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abc
default:
result = sdk.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path)).Result()
}
value := app.cdc.MustMarshalBinary(result)
// Encode with json
value := wire.Cdc.MustMarshalBinary(result)
return abci.ResponseQuery{
Code: uint32(sdk.ABCICodeOK),
Value: value,

View File

@ -30,7 +30,7 @@ func newBaseApp(name string) *BaseApp {
db := dbm.NewMemDB()
codec := wire.NewCodec()
registerTestCodec(codec)
return NewBaseApp(name, codec, logger, db)
return NewBaseApp(name, logger, db, testTxDecoder(codec))
}
func registerTestCodec(cdc *wire.Codec) {
@ -49,8 +49,6 @@ func setupBaseApp(t *testing.T) (*BaseApp, *sdk.KVStoreKey, *sdk.KVStoreKey) {
app := newBaseApp(t.Name())
require.Equal(t, t.Name(), app.Name())
app.SetTxDecoder(testTxDecoder(app.cdc))
// make some cap keys
capKey1 := sdk.NewKVStoreKey("key1")
capKey2 := sdk.NewKVStoreKey("key2")
@ -85,7 +83,7 @@ func TestLoadVersion(t *testing.T) {
logger := defaultLogger()
db := dbm.NewMemDB()
name := t.Name()
app := NewBaseApp(name, nil, logger, db)
app := NewBaseApp(name, logger, db, nil)
// make a cap key and mount the store
capKey := sdk.NewKVStoreKey("main")
@ -114,7 +112,7 @@ func TestLoadVersion(t *testing.T) {
commitID2 := sdk.CommitID{2, res.Data}
// reload with LoadLatestVersion
app = NewBaseApp(name, nil, logger, db)
app = NewBaseApp(name, logger, db, nil)
app.MountStoresIAVL(capKey)
err = app.LoadLatestVersion(capKey)
require.Nil(t, err)
@ -122,7 +120,7 @@ func TestLoadVersion(t *testing.T) {
// reload with LoadVersion, see if you can commit the same block and get
// the same result
app = NewBaseApp(name, nil, logger, db)
app = NewBaseApp(name, logger, db, nil)
app.MountStoresIAVL(capKey)
err = app.LoadVersion(1, capKey)
require.Nil(t, err)
@ -142,9 +140,7 @@ func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, exp
func TestOptionFunction(t *testing.T) {
logger := defaultLogger()
db := dbm.NewMemDB()
codec := wire.NewCodec()
registerTestCodec(codec)
bap := NewBaseApp("starting name", codec, logger, db, testChangeNameHelper("new name"))
bap := NewBaseApp("starting name", logger, db, nil, testChangeNameHelper("new name"))
require.Equal(t, bap.name, "new name", "BaseApp should have had name changed via option function")
}
@ -216,7 +212,7 @@ func TestInitChainer(t *testing.T) {
// we can reload the same app later
db := dbm.NewMemDB()
logger := defaultLogger()
app := NewBaseApp(name, nil, logger, db)
app := NewBaseApp(name, logger, db, nil)
capKey := sdk.NewKVStoreKey("main")
capKey2 := sdk.NewKVStoreKey("key2")
app.MountStoresIAVL(capKey, capKey2)
@ -257,7 +253,7 @@ func TestInitChainer(t *testing.T) {
require.Equal(t, value, res.Value)
// reload app
app = NewBaseApp(name, nil, logger, db)
app = NewBaseApp(name, logger, db, nil)
app.MountStoresIAVL(capKey, capKey2)
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
require.Nil(t, err)
@ -444,9 +440,13 @@ func TestCheckTx(t *testing.T) {
app.InitChain(abci.RequestInitChain{})
// Create same codec used in txDecoder
codec := wire.NewCodec()
registerTestCodec(codec)
for i := int64(0); i < nTxs; i++ {
tx := newTxCounter(i, 0)
txBytes, err := app.cdc.MarshalBinary(tx)
txBytes, err := codec.MarshalBinary(tx)
require.NoError(t, err)
r := app.CheckTx(txBytes)
assert.True(t, r.IsOK(), fmt.Sprintf("%v", r))
@ -481,6 +481,10 @@ func TestDeliverTx(t *testing.T) {
deliverKey := []byte("deliver-key")
app.Router().AddRoute(typeMsgCounter, handlerMsgCounter(t, capKey, deliverKey))
// Create same codec used in txDecoder
codec := wire.NewCodec()
registerTestCodec(codec)
nBlocks := 3
txPerHeight := 5
for blockN := 0; blockN < nBlocks; blockN++ {
@ -488,7 +492,7 @@ func TestDeliverTx(t *testing.T) {
for i := 0; i < txPerHeight; i++ {
counter := int64(blockN*txPerHeight + i)
tx := newTxCounter(counter, counter)
txBytes, err := app.cdc.MarshalBinary(tx)
txBytes, err := codec.MarshalBinary(tx)
require.NoError(t, err)
res := app.DeliverTx(txBytes)
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
@ -518,12 +522,16 @@ func TestMultiMsgDeliverTx(t *testing.T) {
app.Router().AddRoute(typeMsgCounter, handlerMsgCounter(t, capKey, deliverKey))
app.Router().AddRoute(typeMsgCounter2, handlerMsgCounter(t, capKey, deliverKey2))
// Create same codec used in txDecoder
codec := wire.NewCodec()
registerTestCodec(codec)
// run a multi-msg tx
// with all msgs the same type
{
app.BeginBlock(abci.RequestBeginBlock{})
tx := newTxCounter(0, 0, 1, 2)
txBytes, err := app.cdc.MarshalBinary(tx)
txBytes, err := codec.MarshalBinary(tx)
require.NoError(t, err)
res := app.DeliverTx(txBytes)
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
@ -544,7 +552,7 @@ func TestMultiMsgDeliverTx(t *testing.T) {
tx := newTxCounter(1, 3)
tx.Msgs = append(tx.Msgs, msgCounter2{0})
tx.Msgs = append(tx.Msgs, msgCounter2{1})
txBytes, err := app.cdc.MarshalBinary(tx)
txBytes, err := codec.MarshalBinary(tx)
require.NoError(t, err)
res := app.DeliverTx(txBytes)
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
@ -589,6 +597,10 @@ func TestSimulateTx(t *testing.T) {
})
app.InitChain(abci.RequestInitChain{})
// Create same codec used in txDecoder
codec := wire.NewCodec()
registerTestCodec(codec)
nBlocks := 3
for blockN := 0; blockN < nBlocks; blockN++ {
count := int64(blockN + 1)
@ -607,7 +619,7 @@ func TestSimulateTx(t *testing.T) {
require.Equal(t, int64(gasConsumed), result.GasUsed)
// simulate by calling Query with encoded tx
txBytes, err := app.cdc.MarshalBinary(tx)
txBytes, err := codec.MarshalBinary(tx)
require.Nil(t, err)
query := abci.RequestQuery{
Path: "/app/simulate",
@ -617,7 +629,8 @@ func TestSimulateTx(t *testing.T) {
require.True(t, queryResult.IsOK(), queryResult.Log)
var res sdk.Result
app.cdc.MustUnmarshalBinary(queryResult.Value, &res)
wire.Cdc.MustUnmarshalBinary(queryResult.Value, &res)
require.Nil(t, err, "Result unmarshalling failed")
require.True(t, res.IsOK(), res.Log)
require.Equal(t, gasConsumed, res.GasUsed, res.Log)
app.EndBlock(abci.RequestEndBlock{})

View File

@ -63,7 +63,7 @@ type GaiaApp struct {
func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
cdc := MakeCodec()
bApp := bam.NewBaseApp(appName, cdc, logger, db, baseAppOptions...)
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(traceStore)
var app = &GaiaApp{

View File

@ -149,7 +149,7 @@ type GaiaApp struct {
func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
cdc := MakeCodec()
bApp := bam.NewBaseApp(appName, cdc, logger, db, baseAppOptions...)
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(os.Stdout)
// create your application object

View File

@ -421,17 +421,13 @@ Here is the complete setup for App1:
```go
func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
cdc := wire.NewCodec()
// Create the base application object.
app := bapp.NewBaseApp(app1Name, cdc, logger, db)
app := bapp.NewBaseApp(app1Name, logger, db, tx1Decoder)
// Create a capability key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
// Determine how transactions are decoded.
app.SetTxDecoder(txDecoder)
// Register message routes.
// Note the handler receives the keyAccount and thus
// gets access to the account store.
@ -458,7 +454,7 @@ Here, we have only a single Msg type, `bank`, a single store for accounts, and a
The handler is granted access to the store by giving it the capability key.
In future apps, we'll have multiple stores and handlers, and not every handler will get access to every store.
After setting the transaction decoder and the message handling routes, the final
After setting the message handling routes, the final
step is to mount the stores and load the latest version.
Since we only have one store, we only mount one.

View File

@ -169,10 +169,19 @@ type app2Tx struct {
func (tx app2Tx) GetMsgs() []sdk.Msg {
return []sdk.Msg{tx.Msg}
}
```
We don't need a custom TxDecoder function anymore, since we're just using the
Amino codec!
// Amino decode app2Tx. Capable of decoding both MsgSend and MsgIssue
func tx2Decoder(cdc *wire.Codec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx app2Tx
err := cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode(err.Error())
}
return tx, nil
}
}
```
## AnteHandler
@ -249,7 +258,7 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp {
cdc := NewCodec()
// Create the base application object.
app := bapp.NewBaseApp(app2Name, cdc, logger, db)
app := bapp.NewBaseApp(app2Name, logger, db, txDecoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
@ -280,9 +289,8 @@ key for a second store that is *only* passed to a second handler, the
`handleMsgIssue`. The first `handleMsgSend` has no access to this second store and cannot read or write to
it, ensuring a strong separation of concerns.
Note also that we do not need to use `SetTxDecoder` here - now that we're using
Amino, we simply create a codec, register our types on the codec, and pass the
codec into `NewBaseApp`. The SDK takes care of the rest for us!
Note now that we're using Amino, we create a codec, register our types on the codec, and pass the
codec into our TxDecoder constructor, `tx2Decoder`. The SDK takes care of the rest for us!
## Conclusion

View File

@ -328,7 +328,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
cdc := NewCodec()
// Create the base application object.
app := bapp.NewBaseApp(app3Name, cdc, logger, db)
app := bapp.NewBaseApp(app3Name, logger, db, auth.DefaultTxDecoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
@ -361,6 +361,9 @@ and receives only the `bank.Keeper`. See the
[x/bank API docs](https://godoc.org/github.com/cosmos/cosmos-sdk/x/bank)
for more details.
We also use the default txDecoder in `x/auth`, which decodes amino-encoded
`auth.StdTx` transactions.
## Conclusion
Armed with native modules for authentication and coin transfer,

View File

@ -9,7 +9,6 @@ import (
bapp "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
const (
@ -18,17 +17,12 @@ const (
func NewApp1(logger log.Logger, db dbm.DB) *bapp.BaseApp {
cdc := wire.NewCodec()
// Create the base application object.
app := bapp.NewBaseApp(app1Name, cdc, logger, db)
app := bapp.NewBaseApp(app1Name, logger, db, tx1Decoder)
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
// Determine how transactions are decoded.
app.SetTxDecoder(txDecoder)
// Register message routes.
// Note the handler gets access to the account store.
app.Router().
@ -225,7 +219,7 @@ func (tx app1Tx) GetMsgs() []sdk.Msg {
}
// JSON decode MsgSend.
func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
func tx1Decoder(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx app1Tx
err := json.Unmarshal(txBytes, &tx)
if err != nil {

View File

@ -37,7 +37,7 @@ func NewApp2(logger log.Logger, db dbm.DB) *bapp.BaseApp {
cdc := NewCodec()
// Create the base application object.
app := bapp.NewBaseApp(app2Name, cdc, logger, db)
app := bapp.NewBaseApp(app2Name, logger, db, tx2Decoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")
@ -191,6 +191,18 @@ func (tx app2Tx) GetSignatures() []auth.StdSignature {
return tx.Signatures
}
// Amino decode app2Tx. Capable of decoding both MsgSend and MsgIssue
func tx2Decoder(cdc *wire.Codec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx app2Tx
err := cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode(err.Error())
}
return tx, nil
}
}
//------------------------------------------------------------------
// Simple anteHandler that ensures msg signers have signed.

View File

@ -21,7 +21,7 @@ func NewApp3(logger log.Logger, db dbm.DB) *bapp.BaseApp {
cdc := NewCodec()
// Create the base application object.
app := bapp.NewBaseApp(app3Name, cdc, logger, db)
app := bapp.NewBaseApp(app3Name, logger, db, auth.DefaultTxDecoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")

View File

@ -22,7 +22,7 @@ func NewApp4(logger log.Logger, db dbm.DB) *bapp.BaseApp {
cdc := NewCodec()
// Create the base application object.
app := bapp.NewBaseApp(app3Name, cdc, logger, db)
app := bapp.NewBaseApp(app4Name, logger, db, auth.DefaultTxDecoder(cdc))
// Create a key for accessing the account store.
keyAccount := sdk.NewKVStoreKey("acc")

View File

@ -53,7 +53,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.Ba
// create your application type
var app = &BasecoinApp{
cdc: cdc,
BaseApp: bam.NewBaseApp(appName, cdc, logger, db, baseAppOptions...),
BaseApp: bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...),
keyMain: sdk.NewKVStoreKey("main"),
keyAccount: sdk.NewKVStoreKey("acc"),
keyIBC: sdk.NewKVStoreKey("ibc"),

View File

@ -58,7 +58,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
// Create your application object.
var app = &DemocoinApp{
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
BaseApp: bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc)),
cdc: cdc,
capKeyMainStore: sdk.NewKVStoreKey("main"),
capKeyAccountStore: sdk.NewKVStoreKey("acc"),

View File

@ -32,14 +32,11 @@ func main() {
var capKeyMainStore = sdk.NewKVStoreKey("main")
// Create BaseApp.
var baseApp = bam.NewBaseApp("kvstore", nil, logger, db)
var baseApp = bam.NewBaseApp("kvstore", logger, db, decodeTx)
// Set mounts for BaseApp's MultiStore.
baseApp.MountStoresIAVL(capKeyMainStore)
// Set Tx decoder
baseApp.SetTxDecoder(decodeTx)
// Set a handler Route.
baseApp.Router().AddRoute("kvstore", Handler(capKeyMainStore))

View File

@ -30,14 +30,11 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
capKeyMainStore := sdk.NewKVStoreKey("main")
// Create BaseApp.
baseApp := bam.NewBaseApp("kvstore", nil, logger, db)
baseApp := bam.NewBaseApp("kvstore", logger, db, decodeTx)
// Set mounts for BaseApp's MultiStore.
baseApp.MountStoresIAVL(capKeyMainStore)
// Set Tx decoder
baseApp.SetTxDecoder(decodeTx)
baseApp.SetInitChainer(InitChainer(capKeyMainStore))
// Set a handler Route.

View File

@ -17,11 +17,12 @@ const (
// NewAnteHandler returns an AnteHandler that checks
// and increments sequence numbers, checks signatures & account numbers,
// and deducts fees from the first signer.
// nolint: gocyclo
func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
return func(
ctx sdk.Context, tx sdk.Tx,
) (_ sdk.Context, _ sdk.Result, abort bool) {
) (newCtx sdk.Context, res sdk.Result, abort bool) {
// This AnteHandler requires Txs to be StdTxs
stdTx, ok := tx.(StdTx)
@ -29,20 +30,39 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
return ctx, sdk.ErrInternal("tx must be StdTx").Result(), true
}
// set the gas meter
newCtx = ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
// AnteHandlers must have their own defer/recover in order
// for the BaseApp to know how much gas was used!
// This is because the GasMeter is created in the AnteHandler,
// but if it panics the context won't be set properly in runTx's recover ...
defer func() {
if r := recover(); r != nil {
switch rType := r.(type) {
case sdk.ErrorOutOfGas:
log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor)
res = sdk.ErrOutOfGas(log).Result()
res.GasWanted = stdTx.Fee.Gas
res.GasUsed = newCtx.GasMeter().GasConsumed()
abort = true
default:
panic(r)
}
}
}()
err := validateBasic(stdTx)
if err != nil {
return ctx, err.Result(), true
return newCtx, err.Result(), true
}
sigs := stdTx.GetSignatures()
signerAddrs := stdTx.GetSigners()
msgs := tx.GetMsgs()
// set the gas meter
ctx = ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
// charge gas for the memo
ctx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo")
newCtx.GasMeter().ConsumeGas(memoCostPerByte*sdk.Gas(len(stdTx.GetMemo())), "memo")
// Get the sign bytes (requires all account & sequence numbers and the fee)
sequences := make([]int64, len(sigs))
@ -59,38 +79,38 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
signerAddr, sig := signerAddrs[i], sigs[i]
// check signature, return account with incremented nonce
signBytes := StdSignBytes(ctx.ChainID(), accNums[i], sequences[i], fee, msgs, stdTx.GetMemo())
signBytes := StdSignBytes(newCtx.ChainID(), accNums[i], sequences[i], fee, msgs, stdTx.GetMemo())
signerAcc, res := processSig(
ctx, am,
newCtx, am,
signerAddr, sig, signBytes,
)
if !res.IsOK() {
return ctx, res, true
return newCtx, res, true
}
// first sig pays the fees
// TODO: Add min fees
// Can this function be moved outside of the loop?
if i == 0 && !fee.Amount.IsZero() {
ctx.GasMeter().ConsumeGas(deductFeesCost, "deductFees")
newCtx.GasMeter().ConsumeGas(deductFeesCost, "deductFees")
signerAcc, res = deductFees(signerAcc, fee)
if !res.IsOK() {
return ctx, res, true
return newCtx, res, true
}
fck.addCollectedFees(ctx, fee.Amount)
fck.addCollectedFees(newCtx, fee.Amount)
}
// Save the account.
am.SetAccount(ctx, signerAcc)
am.SetAccount(newCtx, signerAcc)
signerAccs[i] = signerAcc
}
// cache the signer accounts in the context
ctx = WithSigners(ctx, signerAccs)
newCtx = WithSigners(newCtx, signerAccs)
// TODO: tx tags (?)
return ctx, sdk.Result{}, false // continue...
return newCtx, sdk.Result{GasWanted: stdTx.Fee.Gas}, false // continue...
}
}

View File

@ -47,21 +47,20 @@ func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx
// run the tx through the anteHandler and ensure it fails with the given code
func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, code sdk.CodeType) {
defer func() {
if r := recover(); r != nil {
switch r.(type) {
case sdk.ErrorOutOfGas:
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOutOfGas),
fmt.Sprintf("Expected ErrorOutOfGas, got %v", r))
default:
panic(r)
}
}
}()
_, result, abort := anteHandler(ctx, tx)
newCtx, result, abort := anteHandler(ctx, tx)
require.True(t, abort)
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code,
fmt.Sprintf("Expected %v, got %v", sdk.ToABCICode(sdk.CodespaceRoot, code), result))
if code == sdk.CodeOutOfGas {
stdTx, ok := tx.(StdTx)
require.True(t, ok, "tx must be in form auth.StdTx")
// GasWanted set correctly
require.Equal(t, stdTx.Fee.Gas, result.GasWanted, "Gas wanted not set correctly")
require.True(t, result.GasUsed > result.GasWanted, "GasUsed not greated than GasWanted")
// Check that context is set correctly
require.Equal(t, result.GasUsed, newCtx.GasMeter().GasConsumed(), "Context not updated correctly")
}
}
func newTestTx(ctx sdk.Context, msgs []sdk.Msg, privs []crypto.PrivKey, accNums []int64, seqs []int64, fee StdFee) sdk.Tx {

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/tendermint/tendermint/crypto"
)
@ -162,3 +163,22 @@ type StdSignature struct {
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
}
// logic for standard transaction decoding
func DefaultTxDecoder(cdc *wire.Codec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx = StdTx{}
if len(txBytes) == 0 {
return nil, sdk.ErrTxDecode("txBytes are empty")
}
// StdTx.Msg is an interface. The concrete types
// are registered by MakeTxCodec
err := cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode("").TraceSDK(err.Error())
}
return tx, nil
}
}

View File

@ -47,7 +47,7 @@ func NewApp() *App {
// Create your application object
app := &App{
BaseApp: bam.NewBaseApp("mock", cdc, logger, db),
BaseApp: bam.NewBaseApp("mock", logger, db, auth.DefaultTxDecoder(cdc)),
Cdc: cdc,
KeyMain: sdk.NewKVStoreKey("main"),
KeyAccount: sdk.NewKVStoreKey("acc"),