commit
fae728f35a
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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{})
|
||||
|
||||
@ -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{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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"),
|
||||
|
||||
@ -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"),
|
||||
|
||||
@ -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))
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user