From 1b2422e10e903a9d28c94e45de03afc539106ca0 Mon Sep 17 00:00:00 2001 From: Runchao Han Date: Mon, 30 Sep 2024 12:05:03 +1000 Subject: [PATCH 1/6] new ante module --- app/ante.go | 24 ----- app/ante/ante.go | 88 +++++++++++++++++++ .../ante_btc_validation_decorator.go | 2 +- app/app.go | 50 ++++------- .../keeper/drop_validator_msg_decorator.go | 4 +- .../drop_validator_msg_decorator_test.go | 2 +- 6 files changed, 107 insertions(+), 63 deletions(-) delete mode 100644 app/ante.go create mode 100644 app/ante/ante.go rename app/{ => ante}/ante_btc_validation_decorator.go (99%) diff --git a/app/ante.go b/app/ante.go deleted file mode 100644 index 1cd6b9de..00000000 --- a/app/ante.go +++ /dev/null @@ -1,24 +0,0 @@ -package app - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// WrappedAnteHandler is the wrapped AnteHandler that implements the `AnteDecorator` interface, which has a single function `AnteHandle`. -// It allows us to chain an existing AnteHandler with other decorators by using `sdk.ChainAnteDecorators`. -type WrappedAnteHandler struct { - ah sdk.AnteHandler -} - -// NewWrappedAnteHandler creates a new WrappedAnteHandler for a given AnteHandler. -func NewWrappedAnteHandler(ah sdk.AnteHandler) WrappedAnteHandler { - return WrappedAnteHandler{ah} -} - -func (wah WrappedAnteHandler) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - newCtx, err = wah.ah(ctx, tx, simulate) - if err != nil { - return newCtx, err - } - return next(newCtx, tx, simulate) -} diff --git a/app/ante/ante.go b/app/ante/ante.go new file mode 100644 index 00000000..e2952e8c --- /dev/null +++ b/app/ante/ante.go @@ -0,0 +1,88 @@ +package ante + +import ( + "cosmossdk.io/core/store" + circuitkeeper "cosmossdk.io/x/circuit/keeper" + txsigning "cosmossdk.io/x/tx/signing" + wasmapp "github.com/CosmWasm/wasmd/app" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + bbn "github.com/babylonlabs-io/babylon/types" + btcckeeper "github.com/babylonlabs-io/babylon/x/btccheckpoint/keeper" + epochingkeeper "github.com/babylonlabs-io/babylon/x/epoching/keeper" + sdk "github.com/cosmos/cosmos-sdk/types" + authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" +) + +// NewAnteHandler creates a new AnteHandler for the Babylon chain. +func NewAnteHandler( + accountKeeper authante.AccountKeeper, + bankKeeper authtypes.BankKeeper, + feegrantKeeper authante.FeegrantKeeper, + signModeHandler *txsigning.HandlerMap, + ibcKeeper *ibckeeper.Keeper, + wasmConfig *wasmtypes.WasmConfig, + wasmKeeper *wasmkeeper.Keeper, + circuitKeeper *circuitkeeper.Keeper, + epochingKeeper *epochingkeeper.Keeper, + btcConfig bbn.BtcConfig, + btccKeeper *btcckeeper.Keeper, + txCounterStoreService store.KVStoreService, +) sdk.AnteHandler { + // initialize AnteHandler, which includes + // - authAnteHandler + // - custom wasm ante handler NewLimitSimulationGasDecorator and NewCountTXDecorator + // - Extra decorators introduced in Babylon, such as DropValidatorMsgDecorator that delays validator-related messages + // + // We are using constructor from wasmapp as it introduces custom wasm ante handle decorators + // early in chain of ante handlers. + authAnteHandler, err := wasmapp.NewAnteHandler( + wasmapp.HandlerOptions{ + HandlerOptions: authante.HandlerOptions{ + AccountKeeper: accountKeeper, + BankKeeper: bankKeeper, + SignModeHandler: signModeHandler, + FeegrantKeeper: feegrantKeeper, + SigGasConsumer: authante.DefaultSigVerificationGasConsumer, + }, + IBCKeeper: ibcKeeper, + WasmConfig: wasmConfig, + TXCounterStoreService: txCounterStoreService, + WasmKeeper: wasmKeeper, + CircuitKeeper: circuitKeeper, + }, + ) + + if err != nil { + panic(err) + } + + anteHandler := sdk.ChainAnteDecorators( + NewWrappedAnteHandler(authAnteHandler), + epochingkeeper.NewDropValidatorMsgDecorator(epochingKeeper), + NewBtcValidationDecorator(btcConfig, btccKeeper), + ) + + return anteHandler +} + +// WrappedAnteHandler is the wrapped AnteHandler that implements the `AnteDecorator` interface, which has a single function `AnteHandle`. +// It allows us to chain an existing AnteHandler with other decorators by using `sdk.ChainAnteDecorators`. +type WrappedAnteHandler struct { + ah sdk.AnteHandler +} + +// NewWrappedAnteHandler creates a new WrappedAnteHandler for a given AnteHandler. +func NewWrappedAnteHandler(ah sdk.AnteHandler) WrappedAnteHandler { + return WrappedAnteHandler{ah} +} + +func (wah WrappedAnteHandler) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + newCtx, err = wah.ah(ctx, tx, simulate) + if err != nil { + return newCtx, err + } + return next(newCtx, tx, simulate) +} diff --git a/app/ante_btc_validation_decorator.go b/app/ante/ante_btc_validation_decorator.go similarity index 99% rename from app/ante_btc_validation_decorator.go rename to app/ante/ante_btc_validation_decorator.go index 8e5febfb..4ff1277e 100644 --- a/app/ante_btc_validation_decorator.go +++ b/app/ante/ante_btc_validation_decorator.go @@ -1,4 +1,4 @@ -package app +package ante import ( bbn "github.com/babylonlabs-io/babylon/types" diff --git a/app/app.go b/app/app.go index 8eadadc7..e543ad88 100644 --- a/app/app.go +++ b/app/app.go @@ -20,7 +20,6 @@ import ( feegrantmodule "cosmossdk.io/x/feegrant/module" "cosmossdk.io/x/upgrade" upgradetypes "cosmossdk.io/x/upgrade/types" - wasmapp "github.com/CosmWasm/wasmd/app" "github.com/CosmWasm/wasmd/x/wasm" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" @@ -47,7 +46,6 @@ import ( "github.com/cosmos/cosmos-sdk/types/msgservice" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/auth/ante" authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" @@ -93,6 +91,7 @@ import ( ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" "github.com/spf13/cast" + "github.com/babylonlabs-io/babylon/app/ante" "github.com/babylonlabs-io/babylon/app/upgrades" bbn "github.com/babylonlabs-io/babylon/types" @@ -108,7 +107,6 @@ import ( "github.com/babylonlabs-io/babylon/x/checkpointing" checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" "github.com/babylonlabs-io/babylon/x/epoching" - epochingkeeper "github.com/babylonlabs-io/babylon/x/epoching/keeper" epochingtypes "github.com/babylonlabs-io/babylon/x/epoching/types" "github.com/babylonlabs-io/babylon/x/finality" finalitytypes "github.com/babylonlabs-io/babylon/x/finality/types" @@ -478,38 +476,20 @@ func NewBabylonApp( app.MountTransientStores(app.GetTransientStoreKeys()) app.MountMemoryStores(app.GetMemoryStoreKeys()) - // initialize AnteHandler, which includes - // - authAnteHandler - // - custom wasm ante handler NewLimitSimulationGasDecorator and NewCountTXDecorator - // - Extra decorators introduced in Babylon, such as DropValidatorMsgDecorator that delays validator-related messages - // - // We are using constructor from wasmapp as it introduces custom wasm ante handle decorators - // early in chain of ante handlers. - authAnteHandler, err := wasmapp.NewAnteHandler( - wasmapp.HandlerOptions{ - HandlerOptions: ante.HandlerOptions{ - AccountKeeper: app.AccountKeeper, - BankKeeper: app.BankKeeper, - SignModeHandler: txConfig.SignModeHandler(), - FeegrantKeeper: app.FeeGrantKeeper, - SigGasConsumer: ante.DefaultSigVerificationGasConsumer, - }, - IBCKeeper: app.IBCKeeper, - WasmConfig: &wasmConfig, - TXCounterStoreService: runtime.NewKVStoreService(app.AppKeepers.GetKey(wasmtypes.StoreKey)), - WasmKeeper: &app.WasmKeeper, - CircuitKeeper: &app.CircuitKeeper, - }, - ) - - if err != nil { - panic(err) - } - - anteHandler := sdk.ChainAnteDecorators( - NewWrappedAnteHandler(authAnteHandler), - epochingkeeper.NewDropValidatorMsgDecorator(app.EpochingKeeper), - NewBtcValidationDecorator(btcConfig, &app.BtcCheckpointKeeper), + // initialize AnteHandler for the app + anteHandler := ante.NewAnteHandler( + app.AccountKeeper, + app.BankKeeper, + app.FeeGrantKeeper, + txConfig.SignModeHandler(), + app.IBCKeeper, + &wasmConfig, + &app.WasmKeeper, + &app.CircuitKeeper, + &app.EpochingKeeper, + btcConfig, + &app.BtcCheckpointKeeper, + runtime.NewKVStoreService(app.AppKeepers.GetKey(wasmtypes.StoreKey)), ) // set proposal extension diff --git a/x/epoching/keeper/drop_validator_msg_decorator.go b/x/epoching/keeper/drop_validator_msg_decorator.go index c6261b1e..7ab644b7 100644 --- a/x/epoching/keeper/drop_validator_msg_decorator.go +++ b/x/epoching/keeper/drop_validator_msg_decorator.go @@ -8,11 +8,11 @@ import ( // DropValidatorMsgDecorator defines an AnteHandler decorator that rejects all messages that might change the validator set. type DropValidatorMsgDecorator struct { - ek Keeper + ek *Keeper } // NewDropValidatorMsgDecorator creates a new DropValidatorMsgDecorator -func NewDropValidatorMsgDecorator(ek Keeper) *DropValidatorMsgDecorator { +func NewDropValidatorMsgDecorator(ek *Keeper) *DropValidatorMsgDecorator { return &DropValidatorMsgDecorator{ ek: ek, } diff --git a/x/epoching/keeper/drop_validator_msg_decorator_test.go b/x/epoching/keeper/drop_validator_msg_decorator_test.go index a6411e37..0880f946 100644 --- a/x/epoching/keeper/drop_validator_msg_decorator_test.go +++ b/x/epoching/keeper/drop_validator_msg_decorator_test.go @@ -24,7 +24,7 @@ func TestDropValidatorMsgDecorator(t *testing.T) { {&stakingtypes.MsgEditValidator{}, false}, } - decorator := NewDropValidatorMsgDecorator(Keeper{}) + decorator := NewDropValidatorMsgDecorator(&Keeper{}) for _, tc := range testCases { res := decorator.IsValidatorRelatedMsg(tc.msg) From 93aa77a5690691c23dca16ae6dd62f2f1feeb488 Mon Sep 17 00:00:00 2001 From: Runchao Han Date: Mon, 30 Sep 2024 12:46:07 +1000 Subject: [PATCH 2/6] fee checker and tests --- app/ante/ante.go | 5 +- app/ante/ante_btc_validation_decorator.go | 4 +- app/ante/fee_checker.go | 66 ++++++++++++++ app/ante/fee_checker_test.go | 100 ++++++++++++++++++++++ app/ante/get_tx_priority_test.go | 60 +++++++++++++ app/app.go | 6 +- app/params/config.go | 12 +++ 7 files changed, 247 insertions(+), 6 deletions(-) create mode 100644 app/ante/fee_checker.go create mode 100644 app/ante/fee_checker_test.go create mode 100644 app/ante/get_tx_priority_test.go diff --git a/app/ante/ante.go b/app/ante/ante.go index e2952e8c..cd7b83a8 100644 --- a/app/ante/ante.go +++ b/app/ante/ante.go @@ -27,7 +27,7 @@ func NewAnteHandler( wasmKeeper *wasmkeeper.Keeper, circuitKeeper *circuitkeeper.Keeper, epochingKeeper *epochingkeeper.Keeper, - btcConfig bbn.BtcConfig, + btcConfig *bbn.BtcConfig, btccKeeper *btcckeeper.Keeper, txCounterStoreService store.KVStoreService, ) sdk.AnteHandler { @@ -46,6 +46,9 @@ func NewAnteHandler( SignModeHandler: signModeHandler, FeegrantKeeper: feegrantKeeper, SigGasConsumer: authante.DefaultSigVerificationGasConsumer, + // CheckTxFeeWithGlobalMinGasPrices will enforce the global minimum + // gas price for all transactions. + TxFeeChecker: CheckTxFeeWithGlobalMinGasPrices, }, IBCKeeper: ibcKeeper, WasmConfig: wasmConfig, diff --git a/app/ante/ante_btc_validation_decorator.go b/app/ante/ante_btc_validation_decorator.go index 4ff1277e..ffe7d21c 100644 --- a/app/ante/ante_btc_validation_decorator.go +++ b/app/ante/ante_btc_validation_decorator.go @@ -9,12 +9,12 @@ import ( ) type BtcValidationDecorator struct { - BtcCfg bbn.BtcConfig + BtcCfg *bbn.BtcConfig btccheckpointKeeper *btccheckpointkeeper.Keeper } func NewBtcValidationDecorator( - cfg bbn.BtcConfig, + cfg *bbn.BtcConfig, k *btccheckpointkeeper.Keeper, ) BtcValidationDecorator { return BtcValidationDecorator{ diff --git a/app/ante/fee_checker.go b/app/ante/fee_checker.go new file mode 100644 index 00000000..48118af2 --- /dev/null +++ b/app/ante/fee_checker.go @@ -0,0 +1,66 @@ +package ante + +import ( + "fmt" + + errors "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + appparams "github.com/babylonlabs-io/babylon/app/params" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerror "github.com/cosmos/cosmos-sdk/types/errors" +) + +const ( + // priorityScalingFactor is a scaling factor to convert the gas price to a priority. + priorityScalingFactor = 1_000_000 +) + +// CheckTxFeeWithGlobalMinGasPrices implements the default fee logic, where the minimum price per +// unit of gas is fixed and set globally, and the tx priority is computed from the gas price. +// adapted from https://github.com/celestiaorg/celestia-app/pull/2985 +func CheckTxFeeWithGlobalMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return nil, 0, errors.Wrap(sdkerror.ErrTxDecode, "Tx must be a FeeTx") + } + + denom := appparams.DefaultBondDenom + + fee := feeTx.GetFee().AmountOf(denom) + gas := feeTx.GetGas() + + // convert the global minimum gas price to a big.Int + globalMinGasPrice, err := sdkmath.LegacyNewDecFromStr(fmt.Sprintf("%f", appparams.GlobalMinGasPrice)) + if err != nil { + return nil, 0, errors.Wrap(err, "invalid GlobalMinGasPrice") + } + + gasInt := sdkmath.NewIntFromUint64(gas) + minFee := globalMinGasPrice.MulInt(gasInt).RoundInt() + + if !fee.GTE(minFee) { + return nil, 0, errors.Wrapf(sdkerror.ErrInsufficientFee, "insufficient fees; got: %s required: %s", fee, minFee) + } + + priority := getTxPriority(feeTx.GetFee(), int64(gas)) + return feeTx.GetFee(), priority, nil +} + +// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price +// provided in a transaction. +// NOTE: This implementation should not be used for txs with multiple coins. +func getTxPriority(fee sdk.Coins, gas int64) int64 { + var priority int64 + for _, c := range fee { + p := c.Amount.Mul(sdkmath.NewInt(priorityScalingFactor)).QuoRaw(gas) + if !p.IsInt64() { + continue + } + // take the lowest priority as the tx priority + if priority == 0 || p.Int64() < priority { + priority = p.Int64() + } + } + + return priority +} diff --git a/app/ante/fee_checker_test.go b/app/ante/fee_checker_test.go new file mode 100644 index 00000000..35d02516 --- /dev/null +++ b/app/ante/fee_checker_test.go @@ -0,0 +1,100 @@ +package ante_test + +import ( + "math" + "testing" + + bbnapp "github.com/babylonlabs-io/babylon/app" + "github.com/babylonlabs-io/babylon/app/ante" + appparams "github.com/babylonlabs-io/babylon/app/params" + "github.com/babylonlabs-io/babylon/testutil/datagen" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" +) + +// TestCheckTxFeeWithGlobalMinGasPrices tests the CheckTxFeeWithGlobalMinGasPrices +// function +// adapted from https://github.com/celestiaorg/celestia-app/pull/2985 +func TestCheckTxFeeWithGlobalMinGasPrices(t *testing.T) { + encCfg := bbnapp.GetEncodingConfig() + + builder := encCfg.TxConfig.NewTxBuilder() + err := builder.SetMsgs( + banktypes.NewMsgSend( + datagen.GenRandomAccount().GetAddress(), + datagen.GenRandomAccount().GetAddress(), + sdk.NewCoins(sdk.NewInt64Coin(appparams.DefaultBondDenom, 10)), + ), + ) + require.NoError(t, err) + + feeAmount := int64(1000) + ctx := sdk.Context{} + + testCases := []struct { + name string + fee sdk.Coins + gasLimit uint64 + appVersion uint64 + expErr bool + }{ + { + name: "bad tx; fee below required minimum", + fee: sdk.NewCoins(sdk.NewInt64Coin(appparams.DefaultBondDenom, feeAmount-1)), + gasLimit: uint64(float64(feeAmount) / appparams.GlobalMinGasPrice), + appVersion: uint64(2), + expErr: true, + }, + { + name: "good tx; fee equal to required minimum", + fee: sdk.NewCoins(sdk.NewInt64Coin(appparams.DefaultBondDenom, feeAmount)), + gasLimit: uint64(float64(feeAmount) / appparams.GlobalMinGasPrice), + appVersion: uint64(2), + expErr: false, + }, + { + name: "good tx; fee above required minimum", + fee: sdk.NewCoins(sdk.NewInt64Coin(appparams.DefaultBondDenom, feeAmount+1)), + gasLimit: uint64(float64(feeAmount) / appparams.GlobalMinGasPrice), + appVersion: uint64(2), + expErr: false, + }, + { + name: "good tx; gas limit and fee are maximum values", + fee: sdk.NewCoins(sdk.NewInt64Coin(appparams.DefaultBondDenom, math.MaxInt64)), + gasLimit: math.MaxUint64, + appVersion: uint64(2), + expErr: false, + }, + { + name: "bad tx; gas limit and fee are 0", + fee: sdk.NewCoins(sdk.NewInt64Coin(appparams.DefaultBondDenom, 0)), + gasLimit: 0, + appVersion: uint64(2), + expErr: false, + }, + { + name: "good tx; minFee = 0.8, rounds up to 1", + fee: sdk.NewCoins(sdk.NewInt64Coin(appparams.DefaultBondDenom, feeAmount)), + gasLimit: 400, + appVersion: uint64(2), + expErr: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + builder.SetGasLimit(tc.gasLimit) + builder.SetFeeAmount(tc.fee) + tx := builder.GetTx() + + _, _, err := ante.CheckTxFeeWithGlobalMinGasPrices(ctx, tx) + if tc.expErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/app/ante/get_tx_priority_test.go b/app/ante/get_tx_priority_test.go new file mode 100644 index 00000000..d4859dd1 --- /dev/null +++ b/app/ante/get_tx_priority_test.go @@ -0,0 +1,60 @@ +package ante + +import ( + "testing" + + appparams "github.com/babylonlabs-io/babylon/app/params" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" +) + +// TestGetTxPriority tests the getTxPriority function +// adapted from https://github.com/celestiaorg/celestia-app/pull/2985 +func TestGetTxPriority(t *testing.T) { + denom := appparams.DefaultBondDenom + + cases := []struct { + name string + fee sdk.Coins + gas int64 + expectedPri int64 + }{ + { + name: "1 bbn fee large gas", + fee: sdk.NewCoins(sdk.NewInt64Coin(denom, 1_000_000)), + gas: 1000000, + expectedPri: 1000000, + }, + { + name: "1 ubbn fee small gas", + fee: sdk.NewCoins(sdk.NewInt64Coin(denom, 1)), + gas: 1, + expectedPri: 1000000, + }, + { + name: "2 ubbn fee small gas", + fee: sdk.NewCoins(sdk.NewInt64Coin(denom, 2)), + gas: 1, + expectedPri: 2000000, + }, + { + name: "1_000_000 bbn fee normal gas tx", + fee: sdk.NewCoins(sdk.NewInt64Coin(denom, 1_000_000_000_000)), + gas: 75000, + expectedPri: 13333333333333, + }, + { + name: "0.001 ubbn gas price", + fee: sdk.NewCoins(sdk.NewInt64Coin(denom, 1_000)), + gas: 1_000_000, + expectedPri: 1000, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + pri := getTxPriority(tc.fee, tc.gas) + assert.Equal(t, tc.expectedPri, pri) + }) + } +} diff --git a/app/app.go b/app/app.go index e543ad88..9f8a2e96 100644 --- a/app/app.go +++ b/app/app.go @@ -478,16 +478,16 @@ func NewBabylonApp( // initialize AnteHandler for the app anteHandler := ante.NewAnteHandler( - app.AccountKeeper, + &app.AccountKeeper, app.BankKeeper, - app.FeeGrantKeeper, + &app.FeeGrantKeeper, txConfig.SignModeHandler(), app.IBCKeeper, &wasmConfig, &app.WasmKeeper, &app.CircuitKeeper, &app.EpochingKeeper, - btcConfig, + &btcConfig, &app.BtcCheckpointKeeper, runtime.NewKVStoreService(app.AppKeepers.GetKey(wasmtypes.StoreKey)), ) diff --git a/app/params/config.go b/app/params/config.go index 3d432267..222752e9 100644 --- a/app/params/config.go +++ b/app/params/config.go @@ -20,6 +20,18 @@ const ( Bech32PrefixAccAddr = "bbn" ) +// taken from https://github.com/celestiaorg/celestia-app/pull/2985 +const ( + // DefaultMinGasPrice is the default min gas price that gets set in the app.toml file. + // The min gas price acts as a filter. Transactions below that limit will not pass + // a nodes `CheckTx` and thus not be proposed by that node. + DefaultMinGasPrice = 0.002 + + // GlobalMinGasPrice is used in the AnteHandler to ensure + // that all transactions have a gas price greater than or equal to this value. + GlobalMinGasPrice = DefaultMinGasPrice +) + var ( // Bech32PrefixAccPub defines the Bech32 prefix of an account's public key. Bech32PrefixAccPub = Bech32PrefixAccAddr + "pub" From 4c746acc4ea9d6426ab8402e3bb390064a26f589 Mon Sep 17 00:00:00 2001 From: Runchao Han Date: Mon, 30 Sep 2024 16:55:36 +1000 Subject: [PATCH 3/6] changelog and gas price --- CHANGELOG.md | 9 +++++++++ test/e2e/btc_staking_e2e_test.go | 8 ++++---- test/e2e/configurer/chain/commands.go | 4 ++-- test/e2e/configurer/chain/commands_btcstaking.go | 2 +- test/e2e/containers/containers.go | 2 +- test/e2e/initialization/node.go | 3 ++- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36afd6fa..ac190164 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## Unreleased +### State Machine Breaking + +* [#107](https://github.com/babylonlabs-io/babylon/pull/107) Implement ADR-027 and +enable in-protocol minimum gas price + +### Bug Fixes + +### Misc Improvements + ## v0.10.1 ### Bug Fixes diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index d73a7757..0b0fda36 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -621,10 +621,10 @@ func (s *BTCStakingTestSuite) Test7BTCDelegationFeeGrant() { s.NoError(err) s.True(stakerBalances.IsZero()) - // the fee payer should have the (feePayerBalanceBeforeBTCDel - fee) == currentBalance + // the fee payer should have the (feePayerBalanceBeforeBTCDel - fee - txfee) == currentBalance feePayerBalances, err := nonValidatorNode.QueryBalances(feePayerAddr.String()) s.NoError(err) - s.Equal(feePayerBalanceBeforeBTCDel.Sub(fees).String(), feePayerBalances.String()) + s.Less(feePayerBalanceBeforeBTCDel.Sub(fees).String(), feePayerBalances.String()) } // Test8BTCDelegationFeeGrantTyped is an end-to-end test to create a BTC delegation @@ -755,10 +755,10 @@ func (s *BTCStakingTestSuite) Test8BTCDelegationFeeGrantTyped() { s.NoError(err) s.Equal(stakerBalance.String(), stakerBalances.String()) - // the fee payer should have the (feePayerBalanceBeforeBTCDel - fee) == currentBalance + // the fee payer should have the (feePayerBalanceBeforeBTCDel - fee - txfee) == currentBalance feePayerBalances, err := node.QueryBalances(feePayerAddr.String()) s.NoError(err) - s.Equal(feePayerBalanceBeforeBTCDel.Sub(fees).String(), feePayerBalances.String()) + s.Less(feePayerBalanceBeforeBTCDel.Sub(fees).String(), feePayerBalances.String()) } // ParseRespsBTCDelToBTCDel parses an BTC delegation response to BTC Delegation diff --git a/test/e2e/configurer/chain/commands.go b/test/e2e/configurer/chain/commands.go index feca5964..73c6e188 100644 --- a/test/e2e/configurer/chain/commands.go +++ b/test/e2e/configurer/chain/commands.go @@ -258,7 +258,7 @@ func (n *NodeConfig) FinalizeSealedEpochs(startEpoch uint64, lastEpoch uint64) { func (n *NodeConfig) StoreWasmCode(wasmFile, from string) { n.LogActionF("storing wasm code from file %s", wasmFile) - cmd := []string{"babylond", "tx", "wasm", "store", wasmFile, fmt.Sprintf("--from=%s", from), "--gas=auto", "--gas-prices=1ubbn", "--gas-adjustment=1.3"} + cmd := []string{"babylond", "tx", "wasm", "store", wasmFile, fmt.Sprintf("--from=%s", from), "--gas=auto", "--gas-adjustment=1.3"} n.LogActionF(strings.Join(cmd, " ")) _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainId, n.Name, cmd) require.NoError(n.t, err) @@ -267,7 +267,7 @@ func (n *NodeConfig) StoreWasmCode(wasmFile, from string) { func (n *NodeConfig) InstantiateWasmContract(codeId, initMsg, from string) { n.LogActionF("instantiating wasm contract %s with %s", codeId, initMsg) - cmd := []string{"babylond", "tx", "wasm", "instantiate", codeId, initMsg, fmt.Sprintf("--from=%s", from), "--no-admin", "--label=contract", "--gas=auto", "--gas-prices=1ubbn", "--gas-adjustment=1.3"} + cmd := []string{"babylond", "tx", "wasm", "instantiate", codeId, initMsg, fmt.Sprintf("--from=%s", from), "--no-admin", "--label=contract", "--gas=auto", "--gas-adjustment=1.3"} n.LogActionF(strings.Join(cmd, " ")) _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainId, n.Name, cmd) require.NoError(n.t, err) diff --git a/test/e2e/configurer/chain/commands_btcstaking.go b/test/e2e/configurer/chain/commands_btcstaking.go index f7586d81..6faa2d87 100644 --- a/test/e2e/configurer/chain/commands_btcstaking.go +++ b/test/e2e/configurer/chain/commands_btcstaking.go @@ -137,7 +137,7 @@ func (n *NodeConfig) AddCovenantSigs(covPK *bbn.BIP340PubKey, stakingTxHash stri // used key cmd = append(cmd, "--from=val") // gas - cmd = append(cmd, "--gas=auto", "--gas-prices=1ubbn", "--gas-adjustment=1.3") + cmd = append(cmd, "--gas=auto", "--gas-adjustment=1.3") _, _, err := n.containerManager.ExecTxCmd(n.t, n.chainId, n.Name, cmd) require.NoError(n.t, err) diff --git a/test/e2e/containers/containers.go b/test/e2e/containers/containers.go index cd09f1ae..62929b30 100644 --- a/test/e2e/containers/containers.go +++ b/test/e2e/containers/containers.go @@ -69,7 +69,7 @@ func (m *Manager) ExecTxCmd(t *testing.T, chainId string, nodeName string, comma // namely adding flags `--chain-id={chain-id} -b=block --yes --keyring-backend=test "--log_format=json"`, // and searching for `successStr` func (m *Manager) ExecTxCmdWithSuccessString(t *testing.T, chainId string, containerName string, command []string, successStr string) (bytes.Buffer, bytes.Buffer, error) { - allTxArgs := []string{fmt.Sprintf("--chain-id=%s", chainId), "-b=sync", "--yes", "--keyring-backend=test", "--log_format=json", "--home=/home/babylon/babylondata"} + allTxArgs := []string{fmt.Sprintf("--chain-id=%s", chainId), "--gas-prices=0.002ubbn", "-b=sync", "--yes", "--keyring-backend=test", "--log_format=json", "--home=/home/babylon/babylondata"} txCommand := append(command, allTxArgs...) return m.ExecCmd(t, containerName, txCommand, successStr) } diff --git a/test/e2e/initialization/node.go b/test/e2e/initialization/node.go index b43ba62b..dea6df49 100644 --- a/test/e2e/initialization/node.go +++ b/test/e2e/initialization/node.go @@ -32,6 +32,7 @@ import ( "github.com/spf13/viper" babylonApp "github.com/babylonlabs-io/babylon/app" + appparams "github.com/babylonlabs-io/babylon/app/params" "github.com/babylonlabs-io/babylon/cmd/babylond/cmd" "github.com/babylonlabs-io/babylon/crypto/bls12381" "github.com/babylonlabs-io/babylon/privval" @@ -396,7 +397,7 @@ func (n *internalNode) signMsg(msgs ...sdk.Msg) (*sdktx.Tx, error) { } txBuilder.SetMemo(fmt.Sprintf("%s@%s:26656", n.nodeKey.ID(), n.moniker)) - txBuilder.SetFeeAmount(sdk.NewCoins()) + txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(appparams.DefaultBondDenom, math.NewInt(20000)))) txBuilder.SetGasLimit(uint64(200000 * len(msgs))) addr, err := n.keyInfo.GetAddress() From 81ab31d91d4baf3403be7659ee6f57a51b64385c Mon Sep 17 00:00:00 2001 From: Runchao Han Date: Mon, 30 Sep 2024 19:28:14 +1000 Subject: [PATCH 4/6] fix fee grant e2e --- test/e2e/btc_staking_e2e_test.go | 12 +++++------- test/e2e/configurer/chain/commands_btcstaking.go | 6 ++++++ test/e2e/initialization/config.go | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index 0b0fda36..d4a31ac5 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -15,6 +15,7 @@ import ( sdkmath "cosmossdk.io/math" feegrantcli "cosmossdk.io/x/feegrant/client/cli" + appparams "github.com/babylonlabs-io/babylon/app/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/babylonlabs-io/babylon/app/params" @@ -553,7 +554,6 @@ func (s *BTCStakingTestSuite) Test7BTCDelegationFeeGrant() { granteeStakerAddr := sdk.MustAccAddressFromBech32(nonValidatorNode.KeysAdd(wGratee)) feePayerBalanceBeforeBTCDel := sdk.NewCoin(params.DefaultBondDenom, sdkmath.NewInt(100000)) - fees := sdk.NewCoin(params.DefaultBondDenom, sdkmath.NewInt(50000)) // fund the granter nonValidatorNode.BankSendFromNode(feePayerAddr.String(), feePayerBalanceBeforeBTCDel.String()) @@ -604,7 +604,6 @@ func (s *BTCStakingTestSuite) Test7BTCDelegationFeeGrant() { wGratee, false, fmt.Sprintf("--fee-granter=%s", feePayerAddr.String()), - fmt.Sprintf("--fees=%s", fees.String()), ) // wait for a block so that above txs take effect @@ -621,10 +620,10 @@ func (s *BTCStakingTestSuite) Test7BTCDelegationFeeGrant() { s.NoError(err) s.True(stakerBalances.IsZero()) - // the fee payer should have the (feePayerBalanceBeforeBTCDel - fee - txfee) == currentBalance + // the fee payer should have the feePayerBalanceBeforeBTCDel > currentBalance feePayerBalances, err := nonValidatorNode.QueryBalances(feePayerAddr.String()) s.NoError(err) - s.Less(feePayerBalanceBeforeBTCDel.Sub(fees).String(), feePayerBalances.String()) + s.True(feePayerBalanceBeforeBTCDel.Amount.GT(feePayerBalances.AmountOf(appparams.BaseCoinUnit))) } // Test8BTCDelegationFeeGrantTyped is an end-to-end test to create a BTC delegation @@ -738,7 +737,6 @@ func (s *BTCStakingTestSuite) Test8BTCDelegationFeeGrantTyped() { wGratee, false, fmt.Sprintf("--fee-granter=%s", feePayerAddr.String()), - fmt.Sprintf("--fees=%s", fees.String()), ) // wait for a block so that above txs take effect @@ -755,10 +753,10 @@ func (s *BTCStakingTestSuite) Test8BTCDelegationFeeGrantTyped() { s.NoError(err) s.Equal(stakerBalance.String(), stakerBalances.String()) - // the fee payer should have the (feePayerBalanceBeforeBTCDel - fee - txfee) == currentBalance + // the fee payer should have the feePayerBalanceBeforeBTCDel > currentBalance feePayerBalances, err := node.QueryBalances(feePayerAddr.String()) s.NoError(err) - s.Less(feePayerBalanceBeforeBTCDel.Sub(fees).String(), feePayerBalances.String()) + s.True(feePayerBalanceBeforeBTCDel.Amount.GT(feePayerBalances.AmountOf(appparams.BaseCoinUnit))) } // ParseRespsBTCDelToBTCDel parses an BTC delegation response to BTC Delegation diff --git a/test/e2e/configurer/chain/commands_btcstaking.go b/test/e2e/configurer/chain/commands_btcstaking.go index 6faa2d87..a6469982 100644 --- a/test/e2e/configurer/chain/commands_btcstaking.go +++ b/test/e2e/configurer/chain/commands_btcstaking.go @@ -98,9 +98,15 @@ func (n *NodeConfig) CreateBTCDelegation( n.FlagChainID(), "--log_format=json", } + // gas price + cmd = append(cmd, "--gas-prices=0.002ubbn") + if generateOnly { cmd = append(cmd, "--generate-only") } else { + // gas + cmd = append(cmd, "--gas=auto", "--gas-adjustment=1.3") + // broadcast stuff cmd = append(cmd, "-b=sync", "--yes") } diff --git a/test/e2e/initialization/config.go b/test/e2e/initialization/config.go index cb074552..79a39d00 100644 --- a/test/e2e/initialization/config.go +++ b/test/e2e/initialization/config.go @@ -50,7 +50,7 @@ type NodeConfig struct { const ( // common BabylonDenom = "ubbn" - MinGasPrice = "0.000" + MinGasPrice = "0.002" ValidatorWalletName = "val" BabylonOpReturnTag = "01020304" From 2acf2b63a6b19e54b30788ca9d12e5c01c2343a3 Mon Sep 17 00:00:00 2001 From: Runchao Han Date: Mon, 30 Sep 2024 19:51:17 +1000 Subject: [PATCH 5/6] fix fp commission --- test/e2e/btc_staking_e2e_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/e2e/btc_staking_e2e_test.go b/test/e2e/btc_staking_e2e_test.go index d4a31ac5..eaf5b725 100644 --- a/test/e2e/btc_staking_e2e_test.go +++ b/test/e2e/btc_staking_e2e_test.go @@ -865,6 +865,9 @@ func (s *BTCStakingTestSuite) CreateNodeFP(node *chain.NodeConfig) (newFP *bstyp newFP, err = datagen.GenRandomFinalityProviderWithBTCBabylonSKs(r, fpBTCSK, nodeAddr) s.NoError(err) + // use a higher commission to ensure the reward is more than tx fee of a finality sig + commission := sdkmath.LegacyNewDecWithPrec(20, 2) + newFP.Commission = &commission node.CreateFinalityProvider(newFP.Addr, newFP.BtcPk, newFP.Pop, newFP.Description.Moniker, newFP.Description.Identity, newFP.Description.Website, newFP.Description.SecurityContact, newFP.Description.Details, newFP.Commission) // wait for a block so that above txs take effect From 084a9340db570119abc8524a17b089128a7eeff9 Mon Sep 17 00:00:00 2001 From: Runchao Han Date: Tue, 1 Oct 2024 10:24:25 +1000 Subject: [PATCH 6/6] fix default min gas price --- cmd/babylond/cmd/custom_babylon_config.go | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/cmd/babylond/cmd/custom_babylon_config.go b/cmd/babylond/cmd/custom_babylon_config.go index 6b4e6c9f..6e4c4dfc 100644 --- a/cmd/babylond/cmd/custom_babylon_config.go +++ b/cmd/babylond/cmd/custom_babylon_config.go @@ -1,11 +1,11 @@ package cmd import ( + "fmt" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - sdkmath "cosmossdk.io/math" serverconfig "github.com/cosmos/cosmos-sdk/server/config" - sdk "github.com/cosmos/cosmos-sdk/types" appparams "github.com/babylonlabs-io/babylon/app/params" bbn "github.com/babylonlabs-io/babylon/types" @@ -31,19 +31,9 @@ type BabylonAppConfig struct { func DefaultBabylonAppConfig() *BabylonAppConfig { baseConfig := *serverconfig.DefaultConfig() - // The SDK's default minimum gas price is set to "" (empty value) inside - // app.toml. If left empty by validators, the node will halt on startup. - // However, the chain developer can set a default app.toml value for their - // validators here. - // - // In summary: - // - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their - // own app.toml config, - // - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their - // own app.toml to override, or use this default value. - // - // In app, we set the min gas prices to 0. - baseConfig.MinGasPrices = sdk.NewCoin(appparams.BaseCoinUnit, sdkmath.NewInt(1)).String() + // The SDK's default minimum gas price is set to "0.002ubbn" (empty value) inside + // app.toml, in order to avoid spamming attacks due to transactions with 0 gas price. + baseConfig.MinGasPrices = fmt.Sprintf("%f%s", appparams.GlobalMinGasPrice, appparams.BaseCoinUnit) return &BabylonAppConfig{ Config: baseConfig, Wasm: wasmtypes.DefaultWasmConfig(),