diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 8de849200..60e32afa4 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -23,6 +23,17 @@ import ( // and to avoid affecting the Merkle root. var dbHeaderKey = []byte("header") +type RunTxMode uint8 + +const ( + // Check a transaction + RunTxModeCheck RunTxMode = iota + // Simulate a transaction + RunTxModeSimulate RunTxMode = iota + // Deliver a transaction + RunTxModeDeliver RunTxMode = iota +) + // The ABCI application type BaseApp struct { // initialized on creation @@ -309,13 +320,17 @@ func (app *BaseApp) FilterPeerByPubKey(info string) abci.ResponseQuery { // Implements ABCI. // Delegates to CommitMultiStore if it implements Queryable func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { - path := req.Path + path := strings.Split(req.Path, "/") + // first element is empty string + if len(path) > 0 && path[0] == "" { + path = path[1:] + } + fmt.Sprintf("Path: %v\n", path) // "/app" prefix for special application queries - if strings.HasPrefix(path, "/app") { - query := path[4:] + if len(path) >= 2 && path[0] == "app" { var result sdk.Result - switch query { - case "/simulate": + switch path[1] { + case "simulate": txBytes := req.Data tx, err := app.txDecoder(txBytes) if err != nil { @@ -333,27 +348,23 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { } } // "/store" prefix for store queries - if strings.HasPrefix(path, "/store") { + if len(path) >= 1 && path[0] == "store" { queryable, ok := app.cms.(sdk.Queryable) if !ok { msg := "multistore doesn't support queries" return sdk.ErrUnknownRequest(msg).QueryResult() } - req.Path = req.Path[6:] // slice off "/store" + req.Path = "/" + strings.Join(path[1:], "/") return queryable.Query(req) } // "/p2p" prefix for p2p queries - if strings.HasPrefix(path, "/p2p") { - path = path[4:] - if strings.HasPrefix(path, "/filter") { - path = path[7:] - if strings.HasPrefix(path, "/addr") { - path = path[6:] - return app.FilterPeerByAddrPort(path) + if len(path) >= 4 && path[0] == "p2p" { + if path[1] == "filter" { + if path[2] == "addr" { + return app.FilterPeerByAddrPort(path[3]) } - if strings.HasPrefix(path, "/pubkey") { - path = path[8:] - return app.FilterPeerByPubKey(path) + if path[2] == "pubkey" { + return app.FilterPeerByPubKey(path[3]) } } } @@ -385,7 +396,7 @@ func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) { if err != nil { result = err.Result() } else { - result = app.runTx(true, false, txBytes, tx) + result = app.runTx(RunTxModeCheck, txBytes, tx) } return abci.ResponseCheckTx{ @@ -410,7 +421,7 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { if err != nil { result = err.Result() } else { - result = app.runTx(false, false, txBytes, tx) + result = app.runTx(RunTxModeDeliver, txBytes, tx) } // After-handler hooks. @@ -434,22 +445,22 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) { // nolint - Mostly for testing func (app *BaseApp) Check(tx sdk.Tx) (result sdk.Result) { - return app.runTx(true, false, nil, tx) + return app.runTx(RunTxModeCheck, nil, tx) } // nolint - full tx execution func (app *BaseApp) Simulate(tx sdk.Tx) (result sdk.Result) { - return app.runTx(true, true, nil, tx) + return app.runTx(RunTxModeSimulate, nil, tx) } // nolint func (app *BaseApp) Deliver(tx sdk.Tx) (result sdk.Result) { - return app.runTx(false, false, nil, tx) + return app.runTx(RunTxModeDeliver, nil, tx) } // txBytes may be nil in some cases, eg. in tests. // Also, in the future we may support "internal" transactions. -func (app *BaseApp) runTx(isCheckTx bool, simulateDeliver bool, txBytes []byte, tx sdk.Tx) (result sdk.Result) { +func (app *BaseApp) runTx(mode RunTxMode, txBytes []byte, tx sdk.Tx) (result sdk.Result) { // Handle any panics. defer func() { if r := recover(); r != nil { @@ -479,17 +490,14 @@ func (app *BaseApp) runTx(isCheckTx bool, simulateDeliver bool, txBytes []byte, // Get the context var ctx sdk.Context - if isCheckTx { + if mode == RunTxModeCheck || mode == RunTxModeSimulate { ctx = app.checkState.ctx.WithTxBytes(txBytes) } else { ctx = app.deliverState.ctx.WithTxBytes(txBytes) } - // Create a new zeroed gas meter - ctx = ctx.WithGasMeter(sdk.NewGasMeter(app.txGasLimit)) - // Simulate a DeliverTx for gas calculation - if isCheckTx && simulateDeliver { + if mode == RunTxModeSimulate { ctx = ctx.WithIsCheckTx(false) } @@ -513,7 +521,7 @@ func (app *BaseApp) runTx(isCheckTx bool, simulateDeliver bool, txBytes []byte, // Get the correct cache var msCache sdk.CacheMultiStore - if isCheckTx { + if mode == RunTxModeCheck || mode == RunTxModeSimulate { // CacheWrap app.checkState.ms in case it fails. msCache = app.checkState.CacheMultiStore() ctx = ctx.WithMultiStore(msCache) @@ -529,7 +537,7 @@ func (app *BaseApp) runTx(isCheckTx bool, simulateDeliver bool, txBytes []byte, result.GasUsed = ctx.GasMeter().GasConsumed() // If not a simulated run and result was successful, write to app.checkState.ms or app.deliverState.ms - if !simulateDeliver && result.IsOK() { + if mode != RunTxModeSimulate && result.IsOK() { msCache.Write() } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index e54993648..25de7ef7e 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -305,7 +305,7 @@ func TestSimulateTx(t *testing.T) { app.BeginBlock(abci.RequestBeginBlock{Header: header}) result := app.Simulate(tx) require.Equal(t, result.Code, sdk.ABCICodeOK) - require.Equal(t, result.GasUsed, int64(80)) + require.Equal(t, int64(80), result.GasUsed) counter-- encoded, err := json.Marshal(tx) require.Nil(t, err) @@ -317,8 +317,8 @@ func TestSimulateTx(t *testing.T) { require.Equal(t, queryResult.Code, uint32(sdk.ABCICodeOK)) var res sdk.Result app.cdc.MustUnmarshalBinary(queryResult.Value, &res) - require.Equal(t, res.Code, sdk.ABCICodeOK) - require.Equal(t, res.GasUsed, int64(80)) + require.Equal(t, sdk.ABCICodeOK, res.Code) + require.Equal(t, int64(160), res.GasUsed) app.EndBlock(abci.RequestEndBlock{}) app.Commit() } diff --git a/client/context/helpers.go b/client/context/helpers.go index 47c94c98e..562bde9b4 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -113,6 +113,7 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w ChainID: chainID, Sequences: []int64{sequence}, Msg: msg, + Fee: sdk.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas? } keybase, err := keys.GetKeyBase() diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index 3bca2654b..fd26ce27a 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -40,7 +40,7 @@ var ( manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}} fee = sdk.StdFee{ sdk.Coins{{"foocoin", 0}}, - 0, + 100000, } sendMsg1 = bank.MsgSend{ diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index 034e19860..d0b59f331 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -39,7 +39,7 @@ var ( manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}} fee = sdk.StdFee{ sdk.Coins{{"foocoin", 0}}, - 0, + 100000, } sendMsg1 = bank.MsgSend{ diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index c67782d92..b0f188f10 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -33,7 +33,7 @@ var ( coins = sdk.Coins{{"foocoin", 10}} fee = sdk.StdFee{ sdk.Coins{{"foocoin", 0}}, - 0, + 1000000, } sendMsg = bank.MsgSend{ diff --git a/x/auth/ante.go b/x/auth/ante.go index 69b867e17..248083206 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -92,6 +92,9 @@ func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHan // cache the signer accounts in the context ctx = WithSigners(ctx, signerAccs) + // set the gas meter + ctx = ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas)) + // TODO: tx tags (?) return ctx, sdk.Result{}, false // continue... diff --git a/x/bank/keeper.go b/x/bank/keeper.go index 129ffa792..6ef73c68b 100644 --- a/x/bank/keeper.go +++ b/x/bank/keeper.go @@ -6,6 +6,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +const ( + costGetCoins sdk.Gas = 10 + costHasCoins sdk.Gas = 10 + costSetCoins sdk.Gas = 100 + costSubtractCoins sdk.Gas = 10 + costAddCoins sdk.Gas = 10 +) + // Keeper manages transfers between accounts type Keeper struct { am sdk.AccountMapper @@ -108,7 +116,7 @@ func (keeper ViewKeeper) HasCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coi //______________________________________________________________________________________________ func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins { - ctx.GasMeter().ConsumeGas(10, "getCoins") + ctx.GasMeter().ConsumeGas(costGetCoins, "getCoins") acc := am.GetAccount(ctx, addr) if acc == nil { return sdk.Coins{} @@ -117,7 +125,7 @@ func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins } func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error { - ctx.GasMeter().ConsumeGas(100, "setCoins") + ctx.GasMeter().ConsumeGas(costSetCoins, "setCoins") acc := am.GetAccount(ctx, addr) if acc == nil { acc = am.NewAccountWithAddress(ctx, addr) @@ -129,13 +137,13 @@ func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.C // HasCoins returns whether or not an account has at least amt coins. func hasCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) bool { - ctx.GasMeter().ConsumeGas(10, "hasCoins") + ctx.GasMeter().ConsumeGas(costHasCoins, "hasCoins") return getCoins(ctx, am, addr).IsGTE(amt) } // SubtractCoins subtracts amt from the coins at the addr. func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { - ctx.GasMeter().ConsumeGas(10, "subtractCoins") + ctx.GasMeter().ConsumeGas(costSubtractCoins, "subtractCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Minus(amt) if !newCoins.IsNotNegative() { @@ -148,7 +156,7 @@ func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt // AddCoins adds amt to the coins at the addr. func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) { - ctx.GasMeter().ConsumeGas(10, "addCoins") + ctx.GasMeter().ConsumeGas(costAddCoins, "addCoins") oldCoins := getCoins(ctx, am, addr) newCoins := oldCoins.Plus(amt) if !newCoins.IsNotNegative() {