Sync from fork #74
@ -50,6 +50,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
* (ante) [#1176](https://github.com/evmos/ethermint/pull/1176) Fix invalid tx hashes; Remove `Size_` field and validate `Hash`/`From` fields in ante handler,
|
* (ante) [#1176](https://github.com/evmos/ethermint/pull/1176) Fix invalid tx hashes; Remove `Size_` field and validate `Hash`/`From` fields in ante handler,
|
||||||
recompute eth tx hashes in JSON-RPC APIs to fix old blocks.
|
recompute eth tx hashes in JSON-RPC APIs to fix old blocks.
|
||||||
* (deps) [#1168](https://github.com/evmos/ethermint/pull/1168) Upgrade cosmos-sdk to v0.46.
|
* (deps) [#1168](https://github.com/evmos/ethermint/pull/1168) Upgrade cosmos-sdk to v0.46.
|
||||||
|
* (feemarket) [#1194](https://github.com/evmos/ethermint/pull/1194) Apply feemarket to native cosmos tx.
|
||||||
|
|
||||||
### API Breaking
|
### API Breaking
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
|||||||
if err := options.validate(); err != nil {
|
if err := options.validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(
|
return func(
|
||||||
ctx sdk.Context, tx sdk.Tx, sim bool,
|
ctx sdk.Context, tx sdk.Tx, sim bool,
|
||||||
) (newCtx sdk.Context, err error) {
|
) (newCtx sdk.Context, err error) {
|
||||||
@ -45,6 +46,9 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
|||||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||||
anteHandler = newCosmosAnteHandlerEip712(options)
|
anteHandler = newCosmosAnteHandlerEip712(options)
|
||||||
|
case "/ethermint.types.v1.ExtensionOptionDynamicFeeTx":
|
||||||
|
// cosmos-sdk tx with dynamic fee extension
|
||||||
|
anteHandler = newCosmosAnteHandler(options)
|
||||||
default:
|
default:
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrUnknownExtensionOptions,
|
sdkerrors.ErrUnknownExtensionOptions,
|
||||||
|
@ -305,8 +305,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
"success - DeliverTx EIP712 signed Cosmos Tx with MsgSend",
|
"success - DeliverTx EIP712 signed Cosmos Tx with MsgSend",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
from := acc.GetAddress()
|
from := acc.GetAddress()
|
||||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
|
||||||
gas := uint64(200000)
|
gas := uint64(200000)
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100*int64(gas))))
|
||||||
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9000-1", gas, amount)
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9000-1", gas, amount)
|
||||||
return txBuilder.GetTx()
|
return txBuilder.GetTx()
|
||||||
}, false, false, true,
|
}, false, false, true,
|
||||||
@ -315,9 +315,9 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
"success - DeliverTx EIP712 signed Cosmos Tx with DelegateMsg",
|
"success - DeliverTx EIP712 signed Cosmos Tx with DelegateMsg",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
from := acc.GetAddress()
|
from := acc.GetAddress()
|
||||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20))
|
|
||||||
amount := sdk.NewCoins(coinAmount)
|
|
||||||
gas := uint64(200000)
|
gas := uint64(200000)
|
||||||
|
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100*int64(gas)))
|
||||||
|
amount := sdk.NewCoins(coinAmount)
|
||||||
txBuilder := suite.CreateTestEIP712TxBuilderMsgDelegate(from, privKey, "ethermint_9000-1", gas, amount)
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgDelegate(from, privKey, "ethermint_9000-1", gas, amount)
|
||||||
return txBuilder.GetTx()
|
return txBuilder.GetTx()
|
||||||
}, false, false, true,
|
}, false, false, true,
|
||||||
@ -326,8 +326,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
"fails - DeliverTx EIP712 signed Cosmos Tx with wrong Chain ID",
|
"fails - DeliverTx EIP712 signed Cosmos Tx with wrong Chain ID",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
from := acc.GetAddress()
|
from := acc.GetAddress()
|
||||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
|
||||||
gas := uint64(200000)
|
gas := uint64(200000)
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100*int64(gas))))
|
||||||
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9002-1", gas, amount)
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9002-1", gas, amount)
|
||||||
return txBuilder.GetTx()
|
return txBuilder.GetTx()
|
||||||
}, false, false, false,
|
}, false, false, false,
|
||||||
@ -336,8 +336,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
"fails - DeliverTx EIP712 signed Cosmos Tx with different gas fees",
|
"fails - DeliverTx EIP712 signed Cosmos Tx with different gas fees",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
from := acc.GetAddress()
|
from := acc.GetAddress()
|
||||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
|
||||||
gas := uint64(200000)
|
gas := uint64(200000)
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100*int64(gas))))
|
||||||
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
||||||
txBuilder.SetGasLimit(uint64(300000))
|
txBuilder.SetGasLimit(uint64(300000))
|
||||||
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(30))))
|
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(30))))
|
||||||
@ -348,8 +348,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
"fails - DeliverTx EIP712 signed Cosmos Tx with empty signature",
|
"fails - DeliverTx EIP712 signed Cosmos Tx with empty signature",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
from := acc.GetAddress()
|
from := acc.GetAddress()
|
||||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
|
||||||
gas := uint64(200000)
|
gas := uint64(200000)
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100*int64(gas))))
|
||||||
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
||||||
sigsV2 := signing.SignatureV2{}
|
sigsV2 := signing.SignatureV2{}
|
||||||
txBuilder.SetSignatures(sigsV2)
|
txBuilder.SetSignatures(sigsV2)
|
||||||
@ -360,8 +360,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid sequence",
|
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid sequence",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
from := acc.GetAddress()
|
from := acc.GetAddress()
|
||||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
|
||||||
gas := uint64(200000)
|
gas := uint64(200000)
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100*int64(gas))))
|
||||||
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
||||||
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
@ -380,8 +380,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
|||||||
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid signMode",
|
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid signMode",
|
||||||
func() sdk.Tx {
|
func() sdk.Tx {
|
||||||
from := acc.GetAddress()
|
from := acc.GetAddress()
|
||||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
|
||||||
gas := uint64(200000)
|
gas := uint64(200000)
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(100*int64(gas))))
|
||||||
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
||||||
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/evmos/ethermint/app/ante"
|
"github.com/evmos/ethermint/app/ante"
|
||||||
"github.com/evmos/ethermint/server/config"
|
"github.com/evmos/ethermint/server/config"
|
||||||
"github.com/evmos/ethermint/tests"
|
"github.com/evmos/ethermint/tests"
|
||||||
evmkeeper "github.com/evmos/ethermint/x/evm/keeper"
|
|
||||||
"github.com/evmos/ethermint/x/evm/statedb"
|
"github.com/evmos/ethermint/x/evm/statedb"
|
||||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||||
|
|
||||||
@ -227,7 +226,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
|||||||
baseFee := suite.app.EvmKeeper.GetBaseFee(suite.ctx, ethCfg)
|
baseFee := suite.app.EvmKeeper.GetBaseFee(suite.ctx, ethCfg)
|
||||||
suite.Require().Equal(int64(1000000000), baseFee.Int64())
|
suite.Require().Equal(int64(1000000000), baseFee.Int64())
|
||||||
|
|
||||||
gasPrice := new(big.Int).Add(baseFee, evmkeeper.DefaultPriorityReduction.BigInt())
|
gasPrice := new(big.Int).Add(baseFee, evmtypes.DefaultPriorityReduction.BigInt())
|
||||||
|
|
||||||
tx2GasLimit := uint64(1000000)
|
tx2GasLimit := uint64(1000000)
|
||||||
tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit, gasPrice, nil, nil, nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit, gasPrice, nil, nil, nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
||||||
@ -236,8 +235,8 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
|||||||
|
|
||||||
dynamicFeeTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit,
|
dynamicFeeTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit,
|
||||||
nil, // gasPrice
|
nil, // gasPrice
|
||||||
new(big.Int).Add(baseFee, big.NewInt(evmkeeper.DefaultPriorityReduction.Int64()*2)), // gasFeeCap
|
new(big.Int).Add(baseFee, big.NewInt(evmtypes.DefaultPriorityReduction.Int64()*2)), // gasFeeCap
|
||||||
evmkeeper.DefaultPriorityReduction.BigInt(), // gasTipCap
|
evmtypes.DefaultPriorityReduction.BigInt(), // gasTipCap
|
||||||
nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
||||||
dynamicFeeTx.From = addr.Hex()
|
dynamicFeeTx.From = addr.Hex()
|
||||||
dynamicFeeTxPriority := int64(1)
|
dynamicFeeTxPriority := int64(1)
|
||||||
|
142
app/ante/fee_checker.go
Normal file
142
app/ante/fee_checker.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package ante
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
sdkmath "cosmossdk.io/math"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
|
ethermint "github.com/evmos/ethermint/types"
|
||||||
|
"github.com/evmos/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewDynamicFeeChecker returns a `TxFeeChecker` that applies a dynamic fee to
|
||||||
|
// Cosmos txs using the EIP-1559 fee market logic.
|
||||||
|
// This can be called in both CheckTx and deliverTx modes.
|
||||||
|
// a) feeCap = tx.fees / tx.gas
|
||||||
|
// b) tipFeeCap = tx.MaxPriorityPrice (default) or MaxInt64
|
||||||
|
// - when `ExtensionOptionDynamicFeeTx` is omitted, `tipFeeCap` defaults to `MaxInt64`.
|
||||||
|
// - when london hardfork is not enabled, it fallbacks to SDK default behavior (validator min-gas-prices).
|
||||||
|
// - Tx priority is set to `effectiveGasPrice / DefaultPriorityReduction`.
|
||||||
|
func NewDynamicFeeChecker(k DynamicFeeEVMKeeper) authante.TxFeeChecker {
|
||||||
|
return func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) {
|
||||||
|
feeTx, ok := tx.(sdk.FeeTx)
|
||||||
|
if !ok {
|
||||||
|
return nil, 0, fmt.Errorf("tx must be a FeeTx")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.BlockHeight() == 0 {
|
||||||
|
// genesis transactions: fallback to min-gas-price logic
|
||||||
|
return checkTxFeeWithValidatorMinGasPrices(ctx, feeTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
denom := params.EvmDenom
|
||||||
|
ethCfg := params.ChainConfig.EthereumConfig(k.ChainID())
|
||||||
|
|
||||||
|
baseFee := k.GetBaseFee(ctx, ethCfg)
|
||||||
|
if baseFee == nil {
|
||||||
|
// london hardfork is not enabled: fallback to min-gas-prices logic
|
||||||
|
return checkTxFeeWithValidatorMinGasPrices(ctx, feeTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to `MaxInt64` when there's no extension option.
|
||||||
|
maxPriorityPrice := sdkmath.NewInt(math.MaxInt64)
|
||||||
|
|
||||||
|
// get the priority tip cap from the extension option.
|
||||||
|
if hasExtOptsTx, ok := tx.(authante.HasExtensionOptionsTx); ok {
|
||||||
|
for _, opt := range hasExtOptsTx.GetExtensionOptions() {
|
||||||
|
if extOpt, ok := opt.GetCachedValue().(*ethermint.ExtensionOptionDynamicFeeTx); ok {
|
||||||
|
maxPriorityPrice = extOpt.MaxPriorityPrice
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gas := feeTx.GetGas()
|
||||||
|
feeCoins := feeTx.GetFee()
|
||||||
|
fee := feeCoins.AmountOfNoDenomValidation(denom)
|
||||||
|
|
||||||
|
feeCap := fee.Quo(sdkmath.NewIntFromUint64(gas))
|
||||||
|
baseFeeInt := sdkmath.NewIntFromBigInt(baseFee)
|
||||||
|
|
||||||
|
if feeCap.LT(baseFeeInt) {
|
||||||
|
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient gas prices; got: %s required: %s", feeCap, baseFeeInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the effective gas price using the EIP-1559 logic.
|
||||||
|
effectivePrice := sdkmath.NewIntFromBigInt(types.EffectiveGasPrice(baseFeeInt.BigInt(), feeCap.BigInt(), maxPriorityPrice.BigInt()))
|
||||||
|
|
||||||
|
// NOTE: create a new coins slice without having to validate the denom
|
||||||
|
effectiveFee := sdk.Coins{
|
||||||
|
{
|
||||||
|
Denom: denom,
|
||||||
|
Amount: effectivePrice.Mul(sdkmath.NewIntFromUint64(gas)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
bigPriority := effectivePrice.Sub(baseFeeInt).Quo(types.DefaultPriorityReduction)
|
||||||
|
priority := int64(math.MaxInt64)
|
||||||
|
|
||||||
|
if bigPriority.IsInt64() {
|
||||||
|
priority = bigPriority.Int64()
|
||||||
|
}
|
||||||
|
|
||||||
|
return effectiveFee, priority, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkTxFeeWithValidatorMinGasPrices implements the default fee logic, where the minimum price per
|
||||||
|
// unit of gas is fixed and set by each validator, and the tx priority is computed from the gas price.
|
||||||
|
func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.FeeTx) (sdk.Coins, int64, error) {
|
||||||
|
feeCoins := tx.GetFee()
|
||||||
|
gas := tx.GetGas()
|
||||||
|
minGasPrices := ctx.MinGasPrices()
|
||||||
|
|
||||||
|
// Ensure that the provided fees meet a minimum threshold for the validator,
|
||||||
|
// if this is a CheckTx. This is only for local mempool purposes, and thus
|
||||||
|
// is only ran on check tx.
|
||||||
|
if ctx.IsCheckTx() && !minGasPrices.IsZero() {
|
||||||
|
requiredFees := make(sdk.Coins, len(minGasPrices))
|
||||||
|
|
||||||
|
// Determine the required fees by multiplying each required minimum gas
|
||||||
|
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
|
||||||
|
glDec := sdk.NewDec(int64(gas))
|
||||||
|
|
||||||
|
for i, gp := range minGasPrices {
|
||||||
|
fee := gp.Amount.Mul(glDec)
|
||||||
|
requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !feeCoins.IsAnyGTE(requiredFees) {
|
||||||
|
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
priority := getTxPriority(feeCoins)
|
||||||
|
return feeCoins, priority, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the fee
|
||||||
|
// provided in a transaction.
|
||||||
|
func getTxPriority(fees sdk.Coins) int64 {
|
||||||
|
var priority int64
|
||||||
|
|
||||||
|
for _, fee := range fees {
|
||||||
|
amt := fee.Amount.Quo(types.DefaultPriorityReduction)
|
||||||
|
p := int64(math.MaxInt64)
|
||||||
|
|
||||||
|
if amt.IsInt64() {
|
||||||
|
p = amt.Int64()
|
||||||
|
}
|
||||||
|
|
||||||
|
if priority == 0 || p < priority {
|
||||||
|
priority = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return priority
|
||||||
|
}
|
219
app/ante/fee_checker_test.go
Normal file
219
app/ante/fee_checker_test.go
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
package ante
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/types/module"
|
||||||
|
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/evmos/ethermint/encoding"
|
||||||
|
ethermint "github.com/evmos/ethermint/types"
|
||||||
|
"github.com/evmos/ethermint/x/evm/types"
|
||||||
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||||
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ DynamicFeeEVMKeeper = MockEVMKeeper{}
|
||||||
|
|
||||||
|
type MockEVMKeeper struct {
|
||||||
|
BaseFee *big.Int
|
||||||
|
EnableLondonHF bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockEVMKeeper) GetBaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
|
||||||
|
if m.EnableLondonHF {
|
||||||
|
return m.BaseFee
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockEVMKeeper) GetParams(ctx sdk.Context) evmtypes.Params {
|
||||||
|
return evmtypes.DefaultParams()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MockEVMKeeper) ChainID() *big.Int {
|
||||||
|
return big.NewInt(9000)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSDKTxFeeChecker(t *testing.T) {
|
||||||
|
// testCases:
|
||||||
|
// fallback
|
||||||
|
// genesis tx
|
||||||
|
// checkTx, validate with min-gas-prices
|
||||||
|
// deliverTx, no validation
|
||||||
|
// dynamic fee
|
||||||
|
// with extension option
|
||||||
|
// without extension option
|
||||||
|
// london hardfork enableness
|
||||||
|
encodingConfig := encoding.MakeConfig(module.NewBasicManager())
|
||||||
|
minGasPrices := sdk.NewDecCoins(sdk.NewDecCoin("aphoton", sdk.NewInt(10)))
|
||||||
|
|
||||||
|
genesisCtx := sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger())
|
||||||
|
checkTxCtx := sdk.NewContext(nil, tmproto.Header{Height: 1}, true, log.NewNopLogger()).WithMinGasPrices(minGasPrices)
|
||||||
|
deliverTxCtx := sdk.NewContext(nil, tmproto.Header{Height: 1}, false, log.NewNopLogger())
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
ctx sdk.Context
|
||||||
|
keeper DynamicFeeEVMKeeper
|
||||||
|
buildTx func() sdk.Tx
|
||||||
|
expFees string
|
||||||
|
expPriority int64
|
||||||
|
expSuccess bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"success, genesis tx",
|
||||||
|
genesisCtx,
|
||||||
|
MockEVMKeeper{},
|
||||||
|
func() sdk.Tx {
|
||||||
|
return encodingConfig.TxConfig.NewTxBuilder().GetTx()
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fail, min-gas-prices",
|
||||||
|
checkTxCtx,
|
||||||
|
MockEVMKeeper{},
|
||||||
|
func() sdk.Tx {
|
||||||
|
return encodingConfig.TxConfig.NewTxBuilder().GetTx()
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success, min-gas-prices",
|
||||||
|
checkTxCtx,
|
||||||
|
MockEVMKeeper{},
|
||||||
|
func() sdk.Tx {
|
||||||
|
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
||||||
|
txBuilder.SetGasLimit(1)
|
||||||
|
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10))))
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
},
|
||||||
|
"10aphoton",
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success, min-gas-prices deliverTx",
|
||||||
|
deliverTxCtx,
|
||||||
|
MockEVMKeeper{},
|
||||||
|
func() sdk.Tx {
|
||||||
|
return encodingConfig.TxConfig.NewTxBuilder().GetTx()
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fail, dynamic fee",
|
||||||
|
deliverTxCtx,
|
||||||
|
MockEVMKeeper{
|
||||||
|
EnableLondonHF: true, BaseFee: big.NewInt(1),
|
||||||
|
},
|
||||||
|
func() sdk.Tx {
|
||||||
|
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
||||||
|
txBuilder.SetGasLimit(1)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
},
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success, dynamic fee",
|
||||||
|
deliverTxCtx,
|
||||||
|
MockEVMKeeper{
|
||||||
|
EnableLondonHF: true, BaseFee: big.NewInt(10),
|
||||||
|
},
|
||||||
|
func() sdk.Tx {
|
||||||
|
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
||||||
|
txBuilder.SetGasLimit(1)
|
||||||
|
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10))))
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
},
|
||||||
|
"10aphoton",
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success, dynamic fee priority",
|
||||||
|
deliverTxCtx,
|
||||||
|
MockEVMKeeper{
|
||||||
|
EnableLondonHF: true, BaseFee: big.NewInt(10),
|
||||||
|
},
|
||||||
|
func() sdk.Tx {
|
||||||
|
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
||||||
|
txBuilder.SetGasLimit(1)
|
||||||
|
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10).Mul(types.DefaultPriorityReduction).Add(sdk.NewInt(10)))))
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
},
|
||||||
|
"10000010aphoton",
|
||||||
|
10,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success, dynamic fee empty tipFeeCap",
|
||||||
|
deliverTxCtx,
|
||||||
|
MockEVMKeeper{
|
||||||
|
EnableLondonHF: true, BaseFee: big.NewInt(10),
|
||||||
|
},
|
||||||
|
func() sdk.Tx {
|
||||||
|
txBuilder := encodingConfig.TxConfig.NewTxBuilder().(authtx.ExtensionOptionsTxBuilder)
|
||||||
|
txBuilder.SetGasLimit(1)
|
||||||
|
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10).Mul(types.DefaultPriorityReduction))))
|
||||||
|
|
||||||
|
option, err := codectypes.NewAnyWithValue(ðermint.ExtensionOptionDynamicFeeTx{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
txBuilder.SetExtensionOptions(option)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
},
|
||||||
|
"10aphoton",
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success, dynamic fee tipFeeCap",
|
||||||
|
deliverTxCtx,
|
||||||
|
MockEVMKeeper{
|
||||||
|
EnableLondonHF: true, BaseFee: big.NewInt(10),
|
||||||
|
},
|
||||||
|
func() sdk.Tx {
|
||||||
|
txBuilder := encodingConfig.TxConfig.NewTxBuilder().(authtx.ExtensionOptionsTxBuilder)
|
||||||
|
txBuilder.SetGasLimit(1)
|
||||||
|
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("aphoton", sdk.NewInt(10).Mul(types.DefaultPriorityReduction).Add(sdk.NewInt(10)))))
|
||||||
|
|
||||||
|
option, err := codectypes.NewAnyWithValue(ðermint.ExtensionOptionDynamicFeeTx{
|
||||||
|
MaxPriorityPrice: sdk.NewInt(5).Mul(types.DefaultPriorityReduction),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
txBuilder.SetExtensionOptions(option)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
},
|
||||||
|
"5000010aphoton",
|
||||||
|
5,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
fees, priority, err := NewDynamicFeeChecker(tc.keeper)(tc.ctx, tc.buildTx())
|
||||||
|
if tc.expSuccess {
|
||||||
|
require.Equal(t, tc.expFees, fees.String())
|
||||||
|
require.Equal(t, tc.expPriority, priority)
|
||||||
|
} else {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -14,17 +14,22 @@ import (
|
|||||||
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DynamicFeeEVMKeeper is a subset of EVMKeeper interface that supports dynamic fee checker
|
||||||
|
type DynamicFeeEVMKeeper interface {
|
||||||
|
ChainID() *big.Int
|
||||||
|
GetParams(ctx sdk.Context) evmtypes.Params
|
||||||
|
GetBaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler
|
// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler
|
||||||
type EVMKeeper interface {
|
type EVMKeeper interface {
|
||||||
statedb.Keeper
|
statedb.Keeper
|
||||||
|
DynamicFeeEVMKeeper
|
||||||
|
|
||||||
ChainID() *big.Int
|
|
||||||
GetParams(ctx sdk.Context) evmtypes.Params
|
|
||||||
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) *vm.EVM
|
NewEVM(ctx sdk.Context, msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) *vm.EVM
|
||||||
DeductTxCostsFromUserBalance(
|
DeductTxCostsFromUserBalance(
|
||||||
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
|
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
|
||||||
) (fees sdk.Coins, priority int64, err error)
|
) (fees sdk.Coins, priority int64, err error)
|
||||||
GetBaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int
|
|
||||||
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
|
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
|
||||||
ResetTransientGasUsed(ctx sdk.Context)
|
ResetTransientGasUsed(ctx sdk.Context)
|
||||||
GetTxIndexTransient(ctx sdk.Context) uint64
|
GetTxIndexTransient(ctx sdk.Context) uint64
|
||||||
|
20
app/app.go
20
app/app.go
@ -600,15 +600,17 @@ func NewEthermintApp(
|
|||||||
// use Ethermint's custom AnteHandler
|
// use Ethermint's custom AnteHandler
|
||||||
func (app *EthermintApp) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64) {
|
func (app *EthermintApp) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64) {
|
||||||
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
|
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
|
||||||
AccountKeeper: app.AccountKeeper,
|
AccountKeeper: app.AccountKeeper,
|
||||||
BankKeeper: app.BankKeeper,
|
BankKeeper: app.BankKeeper,
|
||||||
SignModeHandler: txConfig.SignModeHandler(),
|
SignModeHandler: txConfig.SignModeHandler(),
|
||||||
FeegrantKeeper: app.FeeGrantKeeper,
|
FeegrantKeeper: app.FeeGrantKeeper,
|
||||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||||
IBCKeeper: app.IBCKeeper,
|
IBCKeeper: app.IBCKeeper,
|
||||||
EvmKeeper: app.EvmKeeper,
|
EvmKeeper: app.EvmKeeper,
|
||||||
FeeMarketKeeper: app.FeeMarketKeeper,
|
FeeMarketKeeper: app.FeeMarketKeeper,
|
||||||
MaxTxGasWanted: maxGasWanted,
|
MaxTxGasWanted: maxGasWanted,
|
||||||
|
ExtensionOptionChecker: ethermint.HasDynamicFeeExtensionOption,
|
||||||
|
TxFeeChecker: ante.NewDynamicFeeChecker(app.EvmKeeper),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
|
ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
|
||||||
ibchost "github.com/cosmos/ibc-go/v5/modules/core/24-host"
|
ibchost "github.com/cosmos/ibc-go/v5/modules/core/24-host"
|
||||||
|
"github.com/evmos/ethermint/app/ante"
|
||||||
evmenc "github.com/evmos/ethermint/encoding"
|
evmenc "github.com/evmos/ethermint/encoding"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
@ -62,6 +63,32 @@ func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
|
|||||||
bapp.SetFauxMerkleMode()
|
bapp.SetFauxMerkleMode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSimApp disable feemarket on native tx, otherwise the cosmos-sdk simulation tests will fail.
|
||||||
|
func NewSimApp(logger log.Logger, db dbm.DB) (*EthermintApp, error) {
|
||||||
|
encodingConfig := MakeEncodingConfig()
|
||||||
|
app := NewEthermintApp(logger, db, nil, false, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, encodingConfig, simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
||||||
|
// disable feemarket on native tx
|
||||||
|
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
|
||||||
|
AccountKeeper: app.AccountKeeper,
|
||||||
|
BankKeeper: app.BankKeeper,
|
||||||
|
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
|
||||||
|
FeegrantKeeper: app.FeeGrantKeeper,
|
||||||
|
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||||
|
IBCKeeper: app.IBCKeeper,
|
||||||
|
EvmKeeper: app.EvmKeeper,
|
||||||
|
FeeMarketKeeper: app.FeeMarketKeeper,
|
||||||
|
MaxTxGasWanted: 0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
app.SetAnteHandler(anteHandler)
|
||||||
|
if err := app.LoadLatestVersion(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return app, nil
|
||||||
|
}
|
||||||
|
|
||||||
// interBlockCacheOpt returns a BaseApp option function that sets the persistent
|
// interBlockCacheOpt returns a BaseApp option function that sets the persistent
|
||||||
// inter-block write-through cache.
|
// inter-block write-through cache.
|
||||||
func interBlockCacheOpt() func(*baseapp.BaseApp) {
|
func interBlockCacheOpt() func(*baseapp.BaseApp) {
|
||||||
@ -82,8 +109,9 @@ func TestFullAppSimulation(t *testing.T) {
|
|||||||
require.NoError(t, os.RemoveAll(dir))
|
require.NoError(t, os.RemoveAll(dir))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
app, err := NewSimApp(logger, db)
|
||||||
require.Equal(t, appName, app.Name())
|
require.Equal(t, appName, app.Name())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// run randomized simulation
|
// run randomized simulation
|
||||||
_, simParams, simErr := simulation.SimulateFromSeed(
|
_, simParams, simErr := simulation.SimulateFromSeed(
|
||||||
@ -121,8 +149,8 @@ func TestAppImportExport(t *testing.T) {
|
|||||||
require.NoError(t, db.Close())
|
require.NoError(t, db.Close())
|
||||||
require.NoError(t, os.RemoveAll(dir))
|
require.NoError(t, os.RemoveAll(dir))
|
||||||
}()
|
}()
|
||||||
|
app, err := NewSimApp(logger, db)
|
||||||
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
require.NoError(t, err)
|
||||||
require.Equal(t, appName, app.Name())
|
require.Equal(t, appName, app.Name())
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
@ -163,8 +191,9 @@ func TestAppImportExport(t *testing.T) {
|
|||||||
require.NoError(t, os.RemoveAll(newDir))
|
require.NoError(t, os.RemoveAll(newDir))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
newApp := NewEthermintApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
newApp, err := NewSimApp(log.NewNopLogger(), newDB)
|
||||||
require.Equal(t, appName, newApp.Name())
|
require.Equal(t, appName, newApp.Name())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
var genesisState simapp.GenesisState
|
var genesisState simapp.GenesisState
|
||||||
err = json.Unmarshal(exported.AppState, &genesisState)
|
err = json.Unmarshal(exported.AppState, &genesisState)
|
||||||
@ -236,8 +265,9 @@ func TestAppSimulationAfterImport(t *testing.T) {
|
|||||||
require.NoError(t, os.RemoveAll(dir))
|
require.NoError(t, os.RemoveAll(dir))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
app, err := NewSimApp(logger, db)
|
||||||
require.Equal(t, appName, app.Name())
|
require.Equal(t, appName, app.Name())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Run randomized simulation
|
// Run randomized simulation
|
||||||
stopEarly, simParams, simErr := simulation.SimulateFromSeed(
|
stopEarly, simParams, simErr := simulation.SimulateFromSeed(
|
||||||
@ -281,8 +311,9 @@ func TestAppSimulationAfterImport(t *testing.T) {
|
|||||||
require.NoError(t, os.RemoveAll(newDir))
|
require.NoError(t, os.RemoveAll(newDir))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
newApp := NewEthermintApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
newApp, err := NewSimApp(log.NewNopLogger(), newDB)
|
||||||
require.Equal(t, appName, newApp.Name())
|
require.Equal(t, appName, newApp.Name())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
newApp.InitChain(abci.RequestInitChain{
|
newApp.InitChain(abci.RequestInitChain{
|
||||||
ChainId: SimAppChainID,
|
ChainId: SimAppChainID,
|
||||||
@ -333,14 +364,15 @@ func TestAppStateDeterminism(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, interBlockCacheOpt())
|
app, err := NewSimApp(logger, db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
|
"running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
|
||||||
config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
|
config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
|
||||||
)
|
)
|
||||||
|
|
||||||
_, _, err := simulation.SimulateFromSeed(
|
_, _, err = simulation.SimulateFromSeed(
|
||||||
t,
|
t,
|
||||||
os.Stdout,
|
os.Stdout,
|
||||||
app.BaseApp,
|
app.BaseApp,
|
||||||
|
@ -79,6 +79,9 @@
|
|||||||
- [ethermint/types/v1/account.proto](#ethermint/types/v1/account.proto)
|
- [ethermint/types/v1/account.proto](#ethermint/types/v1/account.proto)
|
||||||
- [EthAccount](#ethermint.types.v1.EthAccount)
|
- [EthAccount](#ethermint.types.v1.EthAccount)
|
||||||
|
|
||||||
|
- [ethermint/types/v1/dynamic_fee.proto](#ethermint/types/v1/dynamic_fee.proto)
|
||||||
|
- [ExtensionOptionDynamicFeeTx](#ethermint.types.v1.ExtensionOptionDynamicFeeTx)
|
||||||
|
|
||||||
- [ethermint/types/v1/web3.proto](#ethermint/types/v1/web3.proto)
|
- [ethermint/types/v1/web3.proto](#ethermint/types/v1/web3.proto)
|
||||||
- [ExtensionOptionsWeb3Tx](#ethermint.types.v1.ExtensionOptionsWeb3Tx)
|
- [ExtensionOptionsWeb3Tx](#ethermint.types.v1.ExtensionOptionsWeb3Tx)
|
||||||
|
|
||||||
@ -1134,6 +1137,37 @@ authtypes.BaseAccount type. It is compatible with the auth AccountKeeper.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- end messages -->
|
||||||
|
|
||||||
|
<!-- end enums -->
|
||||||
|
|
||||||
|
<!-- end HasExtensions -->
|
||||||
|
|
||||||
|
<!-- end services -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="ethermint/types/v1/dynamic_fee.proto"></a>
|
||||||
|
<p align="right"><a href="#top">Top</a></p>
|
||||||
|
|
||||||
|
## ethermint/types/v1/dynamic_fee.proto
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="ethermint.types.v1.ExtensionOptionDynamicFeeTx"></a>
|
||||||
|
|
||||||
|
### ExtensionOptionDynamicFeeTx
|
||||||
|
ExtensionOptionDynamicFeeTx is an extension option that specify the maxPrioPrice for cosmos tx
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| `max_priority_price` | [string](#string) | | the same as `max_priority_fee_per_gas` in eip-1559 spec |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- end messages -->
|
<!-- end messages -->
|
||||||
|
|
||||||
<!-- end enums -->
|
<!-- end enums -->
|
||||||
|
15
proto/ethermint/types/v1/dynamic_fee.proto
Normal file
15
proto/ethermint/types/v1/dynamic_fee.proto
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package ethermint.types.v1;
|
||||||
|
|
||||||
|
import "gogoproto/gogo.proto";
|
||||||
|
|
||||||
|
option go_package = "github.com/evmos/ethermint/types";
|
||||||
|
|
||||||
|
// ExtensionOptionDynamicFeeTx is an extension option that specify the maxPrioPrice for cosmos tx
|
||||||
|
message ExtensionOptionDynamicFeeTx {
|
||||||
|
// the same as `max_priority_fee_per_gas` in eip-1559 spec
|
||||||
|
string max_priority_price = 1 [
|
||||||
|
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
|
||||||
|
(gogoproto.nullable) = false
|
||||||
|
];
|
||||||
|
}
|
@ -973,7 +973,6 @@ func (suite *BackendTestSuite) TestGetEthereumMsgsFromTendermintBlock() {
|
|||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||||||
|
|
||||||
suite.SetupTest() // reset test and queries
|
suite.SetupTest() // reset test and queries
|
||||||
|
|
||||||
msgs := suite.backend.GetEthereumMsgsFromTendermintBlock(tc.resBlock, tc.blockRes)
|
msgs := suite.backend.GetEthereumMsgsFromTendermintBlock(tc.resBlock, tc.blockRes)
|
||||||
|
828
tests/integration_tests/cosmoscli.py
Normal file
828
tests/integration_tests/cosmoscli.py
Normal file
@ -0,0 +1,828 @@
|
|||||||
|
import json
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from dateutil.parser import isoparse
|
||||||
|
from pystarport.utils import build_cli_args_safe, interact
|
||||||
|
|
||||||
|
DEFAULT_GAS_PRICE = "5000000000000aphoton"
|
||||||
|
|
||||||
|
|
||||||
|
class ChainCommand:
|
||||||
|
def __init__(self, cmd):
|
||||||
|
self.cmd = cmd
|
||||||
|
|
||||||
|
def __call__(self, cmd, *args, stdin=None, **kwargs):
|
||||||
|
"execute chain-maind"
|
||||||
|
args = " ".join(build_cli_args_safe(cmd, *args, **kwargs))
|
||||||
|
return interact(f"{self.cmd} {args}", input=stdin)
|
||||||
|
|
||||||
|
|
||||||
|
class CosmosCLI:
|
||||||
|
"the apis to interact with wallet and blockchain"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
data_dir,
|
||||||
|
node_rpc,
|
||||||
|
cmd,
|
||||||
|
):
|
||||||
|
self.data_dir = data_dir
|
||||||
|
self._genesis = json.loads(
|
||||||
|
(self.data_dir / "config" / "genesis.json").read_text()
|
||||||
|
)
|
||||||
|
self.chain_id = self._genesis["chain_id"]
|
||||||
|
self.node_rpc = node_rpc
|
||||||
|
self.raw = ChainCommand(cmd)
|
||||||
|
self.output = None
|
||||||
|
self.error = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_rpc_http(self):
|
||||||
|
return "http" + self.node_rpc.removeprefix("tcp")
|
||||||
|
|
||||||
|
def node_id(self):
|
||||||
|
"get tendermint node id"
|
||||||
|
output = self.raw("tendermint", "show-node-id", home=self.data_dir)
|
||||||
|
return output.decode().strip()
|
||||||
|
|
||||||
|
def delete_account(self, name):
|
||||||
|
"delete wallet account in node's keyring"
|
||||||
|
return self.raw(
|
||||||
|
"keys",
|
||||||
|
"delete",
|
||||||
|
name,
|
||||||
|
"-y",
|
||||||
|
"--force",
|
||||||
|
home=self.data_dir,
|
||||||
|
output="json",
|
||||||
|
keyring_backend="test",
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_account(self, name, mnemonic=None):
|
||||||
|
"create new keypair in node's keyring"
|
||||||
|
if mnemonic is None:
|
||||||
|
output = self.raw(
|
||||||
|
"keys",
|
||||||
|
"add",
|
||||||
|
name,
|
||||||
|
home=self.data_dir,
|
||||||
|
output="json",
|
||||||
|
keyring_backend="test",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
output = self.raw(
|
||||||
|
"keys",
|
||||||
|
"add",
|
||||||
|
name,
|
||||||
|
"--recover",
|
||||||
|
home=self.data_dir,
|
||||||
|
output="json",
|
||||||
|
keyring_backend="test",
|
||||||
|
stdin=mnemonic.encode() + b"\n",
|
||||||
|
)
|
||||||
|
return json.loads(output)
|
||||||
|
|
||||||
|
def init(self, moniker):
|
||||||
|
"the node's config is already added"
|
||||||
|
return self.raw(
|
||||||
|
"init",
|
||||||
|
moniker,
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
home=self.data_dir,
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate_genesis(self):
|
||||||
|
return self.raw("validate-genesis", home=self.data_dir)
|
||||||
|
|
||||||
|
def add_genesis_account(self, addr, coins, **kwargs):
|
||||||
|
return self.raw(
|
||||||
|
"add-genesis-account",
|
||||||
|
addr,
|
||||||
|
coins,
|
||||||
|
home=self.data_dir,
|
||||||
|
output="json",
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
def gentx(self, name, coins, min_self_delegation=1, pubkey=None):
|
||||||
|
return self.raw(
|
||||||
|
"gentx",
|
||||||
|
name,
|
||||||
|
coins,
|
||||||
|
min_self_delegation=str(min_self_delegation),
|
||||||
|
home=self.data_dir,
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
keyring_backend="test",
|
||||||
|
pubkey=pubkey,
|
||||||
|
)
|
||||||
|
|
||||||
|
def collect_gentxs(self, gentx_dir):
|
||||||
|
return self.raw("collect-gentxs", gentx_dir, home=self.data_dir)
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
return json.loads(self.raw("status", node=self.node_rpc))
|
||||||
|
|
||||||
|
def block_height(self):
|
||||||
|
return int(self.status()["SyncInfo"]["latest_block_height"])
|
||||||
|
|
||||||
|
def block_time(self):
|
||||||
|
return isoparse(self.status()["SyncInfo"]["latest_block_time"])
|
||||||
|
|
||||||
|
def balances(self, addr):
|
||||||
|
return json.loads(
|
||||||
|
self.raw("query", "bank", "balances", addr, home=self.data_dir)
|
||||||
|
)["balances"]
|
||||||
|
|
||||||
|
def balance(self, addr, denom="aphoton"):
|
||||||
|
denoms = {coin["denom"]: int(coin["amount"]) for coin in self.balances(addr)}
|
||||||
|
return denoms.get(denom, 0)
|
||||||
|
|
||||||
|
def query_tx(self, tx_type, tx_value):
|
||||||
|
tx = self.raw(
|
||||||
|
"query",
|
||||||
|
"tx",
|
||||||
|
"--type",
|
||||||
|
tx_type,
|
||||||
|
tx_value,
|
||||||
|
home=self.data_dir,
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
return json.loads(tx)
|
||||||
|
|
||||||
|
def query_all_txs(self, addr):
|
||||||
|
txs = self.raw(
|
||||||
|
"query",
|
||||||
|
"txs-all",
|
||||||
|
addr,
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
return json.loads(txs)
|
||||||
|
|
||||||
|
def distribution_commission(self, addr):
|
||||||
|
coin = json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query",
|
||||||
|
"distribution",
|
||||||
|
"commission",
|
||||||
|
addr,
|
||||||
|
output="json",
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)["commission"][0]
|
||||||
|
return float(coin["amount"])
|
||||||
|
|
||||||
|
def distribution_community(self):
|
||||||
|
coin = json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query",
|
||||||
|
"distribution",
|
||||||
|
"community-pool",
|
||||||
|
output="json",
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)["pool"][0]
|
||||||
|
return float(coin["amount"])
|
||||||
|
|
||||||
|
def distribution_reward(self, delegator_addr):
|
||||||
|
coin = json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query",
|
||||||
|
"distribution",
|
||||||
|
"rewards",
|
||||||
|
delegator_addr,
|
||||||
|
output="json",
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)["total"][0]
|
||||||
|
return float(coin["amount"])
|
||||||
|
|
||||||
|
def address(self, name, bech="acc"):
|
||||||
|
output = self.raw(
|
||||||
|
"keys",
|
||||||
|
"show",
|
||||||
|
name,
|
||||||
|
"-a",
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
bech=bech,
|
||||||
|
)
|
||||||
|
return output.strip().decode()
|
||||||
|
|
||||||
|
def account(self, addr):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query", "auth", "account", addr, output="json", node=self.node_rpc
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def tx_search(self, events: str):
|
||||||
|
"/tx_search"
|
||||||
|
return json.loads(
|
||||||
|
self.raw("query", "txs", events=events, output="json", node=self.node_rpc)
|
||||||
|
)
|
||||||
|
|
||||||
|
def tx_search_rpc(self, events: str):
|
||||||
|
rsp = requests.get(
|
||||||
|
f"{self.node_rpc_http}/tx_search",
|
||||||
|
params={
|
||||||
|
"query": f'"{events}"',
|
||||||
|
},
|
||||||
|
).json()
|
||||||
|
assert "error" not in rsp, rsp["error"]
|
||||||
|
return rsp["result"]["txs"]
|
||||||
|
|
||||||
|
def tx(self, value, **kwargs):
|
||||||
|
"/tx"
|
||||||
|
default_kwargs = {
|
||||||
|
"home": self.data_dir,
|
||||||
|
}
|
||||||
|
return json.loads(self.raw("query", "tx", value, **(default_kwargs | kwargs)))
|
||||||
|
|
||||||
|
def total_supply(self):
|
||||||
|
return json.loads(
|
||||||
|
self.raw("query", "bank", "total", output="json", node=self.node_rpc)
|
||||||
|
)
|
||||||
|
|
||||||
|
def validator(self, addr):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query",
|
||||||
|
"staking",
|
||||||
|
"validator",
|
||||||
|
addr,
|
||||||
|
output="json",
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def validators(self):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query", "staking", "validators", output="json", node=self.node_rpc
|
||||||
|
)
|
||||||
|
)["validators"]
|
||||||
|
|
||||||
|
def staking_params(self):
|
||||||
|
return json.loads(
|
||||||
|
self.raw("query", "staking", "params", output="json", node=self.node_rpc)
|
||||||
|
)
|
||||||
|
|
||||||
|
def staking_pool(self, bonded=True):
|
||||||
|
return int(
|
||||||
|
json.loads(
|
||||||
|
self.raw("query", "staking", "pool", output="json", node=self.node_rpc)
|
||||||
|
)["bonded_tokens" if bonded else "not_bonded_tokens"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def transfer(self, from_, to, coins, generate_only=False, **kwargs):
|
||||||
|
kwargs.setdefault("gas_prices", DEFAULT_GAS_PRICE)
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"bank",
|
||||||
|
"send",
|
||||||
|
from_,
|
||||||
|
to,
|
||||||
|
coins,
|
||||||
|
"-y",
|
||||||
|
"--generate-only" if generate_only else None,
|
||||||
|
home=self.data_dir,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_delegated_amount(self, which_addr):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query",
|
||||||
|
"staking",
|
||||||
|
"delegations",
|
||||||
|
which_addr,
|
||||||
|
home=self.data_dir,
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
output="json",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def delegate_amount(self, to_addr, amount, from_addr, gas_price=None):
|
||||||
|
if gas_price is None:
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"staking",
|
||||||
|
"delegate",
|
||||||
|
to_addr,
|
||||||
|
amount,
|
||||||
|
"-y",
|
||||||
|
home=self.data_dir,
|
||||||
|
from_=from_addr,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"staking",
|
||||||
|
"delegate",
|
||||||
|
to_addr,
|
||||||
|
amount,
|
||||||
|
"-y",
|
||||||
|
home=self.data_dir,
|
||||||
|
from_=from_addr,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
gas_prices=gas_price,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# to_addr: croclcl1... , from_addr: cro1...
|
||||||
|
def unbond_amount(self, to_addr, amount, from_addr):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"staking",
|
||||||
|
"unbond",
|
||||||
|
to_addr,
|
||||||
|
amount,
|
||||||
|
"-y",
|
||||||
|
home=self.data_dir,
|
||||||
|
from_=from_addr,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# to_validator_addr: crocncl1... , from_from_validator_addraddr: crocl1...
|
||||||
|
def redelegate_amount(
|
||||||
|
self, to_validator_addr, from_validator_addr, amount, from_addr
|
||||||
|
):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"staking",
|
||||||
|
"redelegate",
|
||||||
|
from_validator_addr,
|
||||||
|
to_validator_addr,
|
||||||
|
amount,
|
||||||
|
"-y",
|
||||||
|
home=self.data_dir,
|
||||||
|
from_=from_addr,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# from_delegator can be account name or address
|
||||||
|
def withdraw_all_rewards(self, from_delegator):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"distribution",
|
||||||
|
"withdraw-all-rewards",
|
||||||
|
"-y",
|
||||||
|
from_=from_delegator,
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def make_multisig(self, name, signer1, signer2):
|
||||||
|
self.raw(
|
||||||
|
"keys",
|
||||||
|
"add",
|
||||||
|
name,
|
||||||
|
multisig=f"{signer1},{signer2}",
|
||||||
|
multisig_threshold="2",
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
)
|
||||||
|
|
||||||
|
def sign_multisig_tx(self, tx_file, multi_addr, signer_name):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"sign",
|
||||||
|
tx_file,
|
||||||
|
from_=signer_name,
|
||||||
|
multisig=multi_addr,
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def sign_batch_multisig_tx(
|
||||||
|
self, tx_file, multi_addr, signer_name, account_number, sequence_number
|
||||||
|
):
|
||||||
|
r = self.raw(
|
||||||
|
"tx",
|
||||||
|
"sign-batch",
|
||||||
|
"--offline",
|
||||||
|
tx_file,
|
||||||
|
account_number=account_number,
|
||||||
|
sequence=sequence_number,
|
||||||
|
from_=signer_name,
|
||||||
|
multisig=multi_addr,
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
return r.decode("utf-8")
|
||||||
|
|
||||||
|
def encode_signed_tx(self, signed_tx):
|
||||||
|
return self.raw(
|
||||||
|
"tx",
|
||||||
|
"encode",
|
||||||
|
signed_tx,
|
||||||
|
)
|
||||||
|
|
||||||
|
def sign_tx(self, tx_file, signer):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"sign",
|
||||||
|
tx_file,
|
||||||
|
from_=signer,
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def sign_tx_json(self, tx, signer, max_priority_price=None):
|
||||||
|
if max_priority_price is not None:
|
||||||
|
tx["body"]["extension_options"].append(
|
||||||
|
{
|
||||||
|
"@type": "/ethermint.types.v1.ExtensionOptionDynamicFeeTx",
|
||||||
|
"max_priority_price": str(max_priority_price),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
with tempfile.NamedTemporaryFile("w") as fp:
|
||||||
|
json.dump(tx, fp)
|
||||||
|
fp.flush()
|
||||||
|
return self.sign_tx(fp.name, signer)
|
||||||
|
|
||||||
|
def combine_multisig_tx(self, tx_file, multi_name, signer1_file, signer2_file):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"multisign",
|
||||||
|
tx_file,
|
||||||
|
multi_name,
|
||||||
|
signer1_file,
|
||||||
|
signer2_file,
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def combine_batch_multisig_tx(
|
||||||
|
self, tx_file, multi_name, signer1_file, signer2_file
|
||||||
|
):
|
||||||
|
r = self.raw(
|
||||||
|
"tx",
|
||||||
|
"multisign-batch",
|
||||||
|
tx_file,
|
||||||
|
multi_name,
|
||||||
|
signer1_file,
|
||||||
|
signer2_file,
|
||||||
|
home=self.data_dir,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
return r.decode("utf-8")
|
||||||
|
|
||||||
|
def broadcast_tx(self, tx_file, **kwargs):
|
||||||
|
kwargs.setdefault("broadcast_mode", "block")
|
||||||
|
kwargs.setdefault("output", "json")
|
||||||
|
return json.loads(
|
||||||
|
self.raw("tx", "broadcast", tx_file, node=self.node_rpc, **kwargs)
|
||||||
|
)
|
||||||
|
|
||||||
|
def broadcast_tx_json(self, tx, **kwargs):
|
||||||
|
with tempfile.NamedTemporaryFile("w") as fp:
|
||||||
|
json.dump(tx, fp)
|
||||||
|
fp.flush()
|
||||||
|
return self.broadcast_tx(fp.name, **kwargs)
|
||||||
|
|
||||||
|
def unjail(self, addr):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"slashing",
|
||||||
|
"unjail",
|
||||||
|
"-y",
|
||||||
|
from_=addr,
|
||||||
|
home=self.data_dir,
|
||||||
|
node=self.node_rpc,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_validator(
|
||||||
|
self,
|
||||||
|
amount,
|
||||||
|
moniker=None,
|
||||||
|
commission_max_change_rate="0.01",
|
||||||
|
commission_rate="0.1",
|
||||||
|
commission_max_rate="0.2",
|
||||||
|
min_self_delegation="1",
|
||||||
|
identity="",
|
||||||
|
website="",
|
||||||
|
security_contact="",
|
||||||
|
details="",
|
||||||
|
):
|
||||||
|
"""MsgCreateValidator
|
||||||
|
create the node with create_node before call this"""
|
||||||
|
pubkey = (
|
||||||
|
"'"
|
||||||
|
+ (
|
||||||
|
self.raw(
|
||||||
|
"tendermint",
|
||||||
|
"show-validator",
|
||||||
|
home=self.data_dir,
|
||||||
|
)
|
||||||
|
.strip()
|
||||||
|
.decode()
|
||||||
|
)
|
||||||
|
+ "'"
|
||||||
|
)
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"staking",
|
||||||
|
"create-validator",
|
||||||
|
"-y",
|
||||||
|
from_=self.address("validator"),
|
||||||
|
amount=amount,
|
||||||
|
pubkey=pubkey,
|
||||||
|
min_self_delegation=min_self_delegation,
|
||||||
|
# commision
|
||||||
|
commission_rate=commission_rate,
|
||||||
|
commission_max_rate=commission_max_rate,
|
||||||
|
commission_max_change_rate=commission_max_change_rate,
|
||||||
|
# description
|
||||||
|
moniker=moniker,
|
||||||
|
identity=identity,
|
||||||
|
website=website,
|
||||||
|
security_contact=security_contact,
|
||||||
|
details=details,
|
||||||
|
# basic
|
||||||
|
home=self.data_dir,
|
||||||
|
node=self.node_rpc,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def edit_validator(
|
||||||
|
self,
|
||||||
|
commission_rate=None,
|
||||||
|
moniker=None,
|
||||||
|
identity=None,
|
||||||
|
website=None,
|
||||||
|
security_contact=None,
|
||||||
|
details=None,
|
||||||
|
):
|
||||||
|
"""MsgEditValidator"""
|
||||||
|
options = dict(
|
||||||
|
commission_rate=commission_rate,
|
||||||
|
# description
|
||||||
|
moniker=moniker,
|
||||||
|
identity=identity,
|
||||||
|
website=website,
|
||||||
|
security_contact=security_contact,
|
||||||
|
details=details,
|
||||||
|
)
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"staking",
|
||||||
|
"edit-validator",
|
||||||
|
"-y",
|
||||||
|
from_=self.address("validator"),
|
||||||
|
home=self.data_dir,
|
||||||
|
node=self.node_rpc,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
**{k: v for k, v in options.items() if v is not None},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def gov_propose(self, proposer, kind, proposal, **kwargs):
|
||||||
|
kwargs.setdefault("gas_prices", DEFAULT_GAS_PRICE)
|
||||||
|
if kind == "software-upgrade":
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"gov",
|
||||||
|
"submit-proposal",
|
||||||
|
kind,
|
||||||
|
proposal["name"],
|
||||||
|
"-y",
|
||||||
|
from_=proposer,
|
||||||
|
# content
|
||||||
|
title=proposal.get("title"),
|
||||||
|
description=proposal.get("description"),
|
||||||
|
upgrade_height=proposal.get("upgrade-height"),
|
||||||
|
upgrade_time=proposal.get("upgrade-time"),
|
||||||
|
upgrade_info=proposal.get("upgrade-info"),
|
||||||
|
deposit=proposal.get("deposit"),
|
||||||
|
# basic
|
||||||
|
home=self.data_dir,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif kind == "cancel-software-upgrade":
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"gov",
|
||||||
|
"submit-proposal",
|
||||||
|
kind,
|
||||||
|
"-y",
|
||||||
|
from_=proposer,
|
||||||
|
# content
|
||||||
|
title=proposal.get("title"),
|
||||||
|
description=proposal.get("description"),
|
||||||
|
deposit=proposal.get("deposit"),
|
||||||
|
# basic
|
||||||
|
home=self.data_dir,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
with tempfile.NamedTemporaryFile("w") as fp:
|
||||||
|
json.dump(proposal, fp)
|
||||||
|
fp.flush()
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"gov",
|
||||||
|
"submit-proposal",
|
||||||
|
kind,
|
||||||
|
fp.name,
|
||||||
|
"-y",
|
||||||
|
from_=proposer,
|
||||||
|
# basic
|
||||||
|
home=self.data_dir,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def gov_vote(self, voter, proposal_id, option, **kwargs):
|
||||||
|
kwargs.setdefault("gas_prices", DEFAULT_GAS_PRICE)
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"gov",
|
||||||
|
"vote",
|
||||||
|
proposal_id,
|
||||||
|
option,
|
||||||
|
"-y",
|
||||||
|
from_=voter,
|
||||||
|
home=self.data_dir,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def gov_deposit(self, depositor, proposal_id, amount):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"gov",
|
||||||
|
"deposit",
|
||||||
|
proposal_id,
|
||||||
|
amount,
|
||||||
|
"-y",
|
||||||
|
from_=depositor,
|
||||||
|
home=self.data_dir,
|
||||||
|
node=self.node_rpc,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def query_proposals(self, depositor=None, limit=None, status=None, voter=None):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query",
|
||||||
|
"gov",
|
||||||
|
"proposals",
|
||||||
|
depositor=depositor,
|
||||||
|
count_total=limit,
|
||||||
|
status=status,
|
||||||
|
voter=voter,
|
||||||
|
output="json",
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def query_proposal(self, proposal_id):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query",
|
||||||
|
"gov",
|
||||||
|
"proposal",
|
||||||
|
proposal_id,
|
||||||
|
output="json",
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def query_tally(self, proposal_id):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"query",
|
||||||
|
"gov",
|
||||||
|
"tally",
|
||||||
|
proposal_id,
|
||||||
|
output="json",
|
||||||
|
node=self.node_rpc,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def ibc_transfer(
|
||||||
|
self,
|
||||||
|
from_,
|
||||||
|
to,
|
||||||
|
amount,
|
||||||
|
channel, # src channel
|
||||||
|
target_version, # chain version number of target chain
|
||||||
|
i=0,
|
||||||
|
):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"ibc-transfer",
|
||||||
|
"transfer",
|
||||||
|
"transfer", # src port
|
||||||
|
channel,
|
||||||
|
to,
|
||||||
|
amount,
|
||||||
|
"-y",
|
||||||
|
# FIXME https://github.com/cosmos/cosmos-sdk/issues/8059
|
||||||
|
"--absolute-timeouts",
|
||||||
|
from_=from_,
|
||||||
|
home=self.data_dir,
|
||||||
|
node=self.node_rpc,
|
||||||
|
keyring_backend="test",
|
||||||
|
chain_id=self.chain_id,
|
||||||
|
packet_timeout_height=f"{target_version}-10000000000",
|
||||||
|
packet_timeout_timestamp=0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def export(self):
|
||||||
|
return self.raw("export", home=self.data_dir)
|
||||||
|
|
||||||
|
def unsaferesetall(self):
|
||||||
|
return self.raw("unsafe-reset-all")
|
||||||
|
|
||||||
|
def build_evm_tx(self, raw_tx: str, **kwargs):
|
||||||
|
return json.loads(
|
||||||
|
self.raw(
|
||||||
|
"tx",
|
||||||
|
"evm",
|
||||||
|
"raw",
|
||||||
|
raw_tx,
|
||||||
|
"-y",
|
||||||
|
"--generate-only",
|
||||||
|
home=self.data_dir,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def query_base_fee(self, **kwargs):
|
||||||
|
default_kwargs = {"home": self.data_dir}
|
||||||
|
return int(
|
||||||
|
json.loads(
|
||||||
|
self.raw(
|
||||||
|
"q",
|
||||||
|
"feemarket",
|
||||||
|
"base-fee",
|
||||||
|
**(default_kwargs | kwargs),
|
||||||
|
)
|
||||||
|
)["base_fee"]
|
||||||
|
)
|
@ -8,6 +8,7 @@ import web3
|
|||||||
from pystarport import ports
|
from pystarport import ports
|
||||||
from web3.middleware import geth_poa_middleware
|
from web3.middleware import geth_poa_middleware
|
||||||
|
|
||||||
|
from .cosmoscli import CosmosCLI
|
||||||
from .utils import wait_for_port
|
from .utils import wait_for_port
|
||||||
|
|
||||||
|
|
||||||
@ -53,6 +54,9 @@ class Ethermint:
|
|||||||
self._w3 = None
|
self._w3 = None
|
||||||
self._use_websockets = use
|
self._use_websockets = use
|
||||||
|
|
||||||
|
def cosmos_cli(self, i=0):
|
||||||
|
return CosmosCLI(self.base_dir / f"node{i}", self.node_rpc(i), "ethermintd")
|
||||||
|
|
||||||
|
|
||||||
class Geth:
|
class Geth:
|
||||||
def __init__(self, w3):
|
def __init__(self, w3):
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
from .network import Ethermint
|
from .network import Ethermint
|
||||||
from .utils import KEYS, sign_transaction
|
from .utils import ADDRS, KEYS, eth_to_bech32, sign_transaction, wait_for_new_blocks
|
||||||
|
|
||||||
PRIORITY_REDUCTION = 1000000
|
PRIORITY_REDUCTION = 1000000
|
||||||
|
|
||||||
@ -101,14 +103,95 @@ def test_priority(ethermint: Ethermint):
|
|||||||
|
|
||||||
# the later txs should be included earlier because of higher priority
|
# the later txs should be included earlier because of higher priority
|
||||||
# FIXME there's some non-deterministics due to mempool logic
|
# FIXME there's some non-deterministics due to mempool logic
|
||||||
assert all(included_earlier(r2, r1) for r1, r2 in zip(receipts, receipts[1:]))
|
tx_indexes = [(r.blockNumber, r.transactionIndex) for r in receipts]
|
||||||
|
print(tx_indexes)
|
||||||
|
# the first sent tx are included later, because of lower priority
|
||||||
|
assert all(i1 > i2 for i1, i2 in zip(tx_indexes, tx_indexes[1:]))
|
||||||
|
|
||||||
|
|
||||||
def included_earlier(receipt1, receipt2):
|
def included_earlier(receipt1, receipt2):
|
||||||
"returns true if receipt1 is earlier than receipt2"
|
"returns true if receipt1 is included earlier than receipt2"
|
||||||
if receipt1.blockNumber < receipt2.blockNumber:
|
return (receipt1.blockNumber, receipt1.transactionIndex) < (
|
||||||
return True
|
receipt2.blockNumber,
|
||||||
elif receipt1.blockNumber == receipt2.blockNumber:
|
receipt2.transactionIndex,
|
||||||
return receipt1.transactionIndex < receipt2.transactionIndex
|
)
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
def test_native_tx_priority(ethermint: Ethermint):
|
||||||
|
cli = ethermint.cosmos_cli()
|
||||||
|
base_fee = cli.query_base_fee()
|
||||||
|
print("base_fee", base_fee)
|
||||||
|
test_cases = [
|
||||||
|
{
|
||||||
|
"from": eth_to_bech32(ADDRS["community"]),
|
||||||
|
"to": eth_to_bech32(ADDRS["validator"]),
|
||||||
|
"amount": "1000aphoton",
|
||||||
|
"gas_prices": f"{base_fee + PRIORITY_REDUCTION * 6}aphoton",
|
||||||
|
"max_priority_price": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": eth_to_bech32(ADDRS["signer1"]),
|
||||||
|
"to": eth_to_bech32(ADDRS["signer2"]),
|
||||||
|
"amount": "1000aphoton",
|
||||||
|
"gas_prices": f"{base_fee + PRIORITY_REDUCTION * 6}aphoton",
|
||||||
|
"max_priority_price": PRIORITY_REDUCTION * 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": eth_to_bech32(ADDRS["signer2"]),
|
||||||
|
"to": eth_to_bech32(ADDRS["signer1"]),
|
||||||
|
"amount": "1000aphoton",
|
||||||
|
"gas_prices": f"{base_fee + PRIORITY_REDUCTION * 4}aphoton",
|
||||||
|
"max_priority_price": PRIORITY_REDUCTION * 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": eth_to_bech32(ADDRS["validator"]),
|
||||||
|
"to": eth_to_bech32(ADDRS["community"]),
|
||||||
|
"amount": "1000aphoton",
|
||||||
|
"gas_prices": f"{base_fee + PRIORITY_REDUCTION * 6}aphoton",
|
||||||
|
"max_priority_price": None, # no extension, maximum tipFeeCap
|
||||||
|
},
|
||||||
|
]
|
||||||
|
txs = []
|
||||||
|
expect_priorities = []
|
||||||
|
for tc in test_cases:
|
||||||
|
tx = cli.transfer(
|
||||||
|
tc["from"],
|
||||||
|
tc["to"],
|
||||||
|
tc["amount"],
|
||||||
|
gas_prices=tc["gas_prices"],
|
||||||
|
generate_only=True,
|
||||||
|
)
|
||||||
|
txs.append(
|
||||||
|
cli.sign_tx_json(
|
||||||
|
tx, tc["from"], max_priority_price=tc.get("max_priority_price")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
gas_price = int(tc["gas_prices"].removesuffix("aphoton"))
|
||||||
|
expect_priorities.append(
|
||||||
|
min(
|
||||||
|
get_max_priority_price(tc.get("max_priority_price")),
|
||||||
|
gas_price - base_fee,
|
||||||
|
)
|
||||||
|
// PRIORITY_REDUCTION
|
||||||
|
)
|
||||||
|
assert expect_priorities == [0, 2, 4, 6]
|
||||||
|
|
||||||
|
txhashes = []
|
||||||
|
for tx in txs:
|
||||||
|
rsp = cli.broadcast_tx_json(tx, broadcast_mode="sync")
|
||||||
|
assert rsp["code"] == 0, rsp["raw_log"]
|
||||||
|
txhashes.append(rsp["txhash"])
|
||||||
|
|
||||||
|
print("wait for two new blocks, so the sent txs are all included")
|
||||||
|
wait_for_new_blocks(cli, 2)
|
||||||
|
|
||||||
|
tx_results = [cli.tx_search_rpc(f"tx.hash='{txhash}'")[0] for txhash in txhashes]
|
||||||
|
tx_indexes = [(int(r["height"]), r["index"]) for r in tx_results]
|
||||||
|
print(tx_indexes)
|
||||||
|
# the first sent tx are included later, because of lower priority
|
||||||
|
assert all(i1 > i2 for i1, i2 in zip(tx_indexes, tx_indexes[1:]))
|
||||||
|
|
||||||
|
|
||||||
|
def get_max_priority_price(max_priority_price):
|
||||||
|
"default to max int64 if None"
|
||||||
|
return max_priority_price if max_priority_price is not None else sys.maxsize
|
||||||
|
@ -4,8 +4,10 @@ import socket
|
|||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import bech32
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from eth_account import Account
|
from eth_account import Account
|
||||||
|
from hexbytes import HexBytes
|
||||||
from web3._utils.transactions import fill_nonce, fill_transaction_defaults
|
from web3._utils.transactions import fill_nonce, fill_transaction_defaults
|
||||||
|
|
||||||
load_dotenv(Path(__file__).parent.parent.parent / "scripts/.env")
|
load_dotenv(Path(__file__).parent.parent.parent / "scripts/.env")
|
||||||
@ -64,6 +66,15 @@ def w3_wait_for_new_blocks(w3, n):
|
|||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_new_blocks(cli, n):
|
||||||
|
begin_height = int((cli.status())["SyncInfo"]["latest_block_height"])
|
||||||
|
while True:
|
||||||
|
time.sleep(0.5)
|
||||||
|
cur_height = int((cli.status())["SyncInfo"]["latest_block_height"])
|
||||||
|
if cur_height - begin_height >= n:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def deploy_contract(w3, jsonfile, args=(), key=KEYS["validator"]):
|
def deploy_contract(w3, jsonfile, args=(), key=KEYS["validator"]):
|
||||||
"""
|
"""
|
||||||
deploy contract and return the deployed contract instance
|
deploy contract and return the deployed contract instance
|
||||||
@ -95,3 +106,8 @@ def send_transaction(w3, tx, key=KEYS["validator"]):
|
|||||||
signed = sign_transaction(w3, tx, key)
|
signed = sign_transaction(w3, tx, key)
|
||||||
txhash = w3.eth.send_raw_transaction(signed.rawTransaction)
|
txhash = w3.eth.send_raw_transaction(signed.rawTransaction)
|
||||||
return w3.eth.wait_for_transaction_receipt(txhash)
|
return w3.eth.wait_for_transaction_receipt(txhash)
|
||||||
|
|
||||||
|
|
||||||
|
def eth_to_bech32(addr, prefix=ETHERMINT_ADDRESS_PREFIX):
|
||||||
|
bz = bech32.convertbits(HexBytes(addr), 8, 5)
|
||||||
|
return bech32.bech32_encode(prefix, bz)
|
||||||
|
@ -20,5 +20,6 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
|||||||
registry.RegisterImplementations(
|
registry.RegisterImplementations(
|
||||||
(*tx.TxExtensionOptionI)(nil),
|
(*tx.TxExtensionOptionI)(nil),
|
||||||
&ExtensionOptionsWeb3Tx{},
|
&ExtensionOptionsWeb3Tx{},
|
||||||
|
&ExtensionOptionDynamicFeeTx{},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
11
types/dynamic_fee.go
Normal file
11
types/dynamic_fee.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HasDynamicFeeExtensionOption returns true if the tx implements the `ExtensionOptionDynamicFeeTx` extension option.
|
||||||
|
func HasDynamicFeeExtensionOption(any *codectypes.Any) bool {
|
||||||
|
_, ok := any.GetCachedValue().(*ExtensionOptionDynamicFeeTx)
|
||||||
|
return ok
|
||||||
|
}
|
321
types/dynamic_fee.pb.go
generated
Normal file
321
types/dynamic_fee.pb.go
generated
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||||
|
// source: ethermint/types/v1/dynamic_fee.proto
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
fmt "fmt"
|
||||||
|
github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
_ "github.com/gogo/protobuf/gogoproto"
|
||||||
|
proto "github.com/gogo/protobuf/proto"
|
||||||
|
io "io"
|
||||||
|
math "math"
|
||||||
|
math_bits "math/bits"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||||
|
|
||||||
|
// ExtensionOptionDynamicFeeTx is an extension option that specify the maxPrioPrice for cosmos tx
|
||||||
|
type ExtensionOptionDynamicFeeTx struct {
|
||||||
|
// the same as `max_priority_fee_per_gas` in eip-1559 spec
|
||||||
|
MaxPriorityPrice github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=max_priority_price,json=maxPriorityPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_priority_price"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) Reset() { *m = ExtensionOptionDynamicFeeTx{} }
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*ExtensionOptionDynamicFeeTx) ProtoMessage() {}
|
||||||
|
func (*ExtensionOptionDynamicFeeTx) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_9d7cf05c9992c480, []int{0}
|
||||||
|
}
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) XXX_Unmarshal(b []byte) error {
|
||||||
|
return m.Unmarshal(b)
|
||||||
|
}
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||||
|
if deterministic {
|
||||||
|
return xxx_messageInfo_ExtensionOptionDynamicFeeTx.Marshal(b, m, deterministic)
|
||||||
|
} else {
|
||||||
|
b = b[:cap(b)]
|
||||||
|
n, err := m.MarshalToSizedBuffer(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return b[:n], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) XXX_Merge(src proto.Message) {
|
||||||
|
xxx_messageInfo_ExtensionOptionDynamicFeeTx.Merge(m, src)
|
||||||
|
}
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) XXX_Size() int {
|
||||||
|
return m.Size()
|
||||||
|
}
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) XXX_DiscardUnknown() {
|
||||||
|
xxx_messageInfo_ExtensionOptionDynamicFeeTx.DiscardUnknown(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
var xxx_messageInfo_ExtensionOptionDynamicFeeTx proto.InternalMessageInfo
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*ExtensionOptionDynamicFeeTx)(nil), "ethermint.types.v1.ExtensionOptionDynamicFeeTx")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("ethermint/types/v1/dynamic_fee.proto", fileDescriptor_9d7cf05c9992c480)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor_9d7cf05c9992c480 = []byte{
|
||||||
|
// 232 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x49, 0x2d, 0xc9, 0x48,
|
||||||
|
0x2d, 0xca, 0xcd, 0xcc, 0x2b, 0xd1, 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x2f, 0x33, 0xd4, 0x4f,
|
||||||
|
0xa9, 0xcc, 0x4b, 0xcc, 0xcd, 0x4c, 0x8e, 0x4f, 0x4b, 0x4d, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9,
|
||||||
|
0x17, 0x12, 0x82, 0xab, 0xd2, 0x03, 0xab, 0xd2, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf,
|
||||||
|
0x07, 0x4b, 0xeb, 0x83, 0x58, 0x10, 0x95, 0x4a, 0xd5, 0x5c, 0xd2, 0xae, 0x15, 0x25, 0xa9, 0x79,
|
||||||
|
0xc5, 0x99, 0xf9, 0x79, 0xfe, 0x05, 0x25, 0x99, 0xf9, 0x79, 0x2e, 0x10, 0xd3, 0xdc, 0x52, 0x53,
|
||||||
|
0x43, 0x2a, 0x84, 0x62, 0xb8, 0x84, 0x72, 0x13, 0x2b, 0xe2, 0x0b, 0x8a, 0x32, 0xf3, 0x8b, 0x32,
|
||||||
|
0x4b, 0x2a, 0x41, 0x8c, 0xe4, 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0xbd, 0x13, 0xf7,
|
||||||
|
0xe4, 0x19, 0x6e, 0xdd, 0x93, 0x57, 0x4b, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf,
|
||||||
|
0xd5, 0x4f, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0x86, 0x52, 0xba, 0xc5, 0x29, 0xd9, 0x10, 0x57, 0xea,
|
||||||
|
0x79, 0xe6, 0x95, 0x04, 0x09, 0xe4, 0x26, 0x56, 0x04, 0x40, 0x0d, 0x0a, 0x00, 0x99, 0xe3, 0x64,
|
||||||
|
0x75, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c,
|
||||||
|
0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x0a, 0x48, 0x66, 0xa6, 0x96,
|
||||||
|
0x81, 0x8c, 0x44, 0xf3, 0x77, 0x12, 0x1b, 0xd8, 0xfd, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0x5c, 0xa9, 0x04, 0x48, 0x11, 0x01, 0x00, 0x00,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) Marshal() (dAtA []byte, err error) {
|
||||||
|
size := m.Size()
|
||||||
|
dAtA = make([]byte, size)
|
||||||
|
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return dAtA[:n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) MarshalTo(dAtA []byte) (int, error) {
|
||||||
|
size := m.Size()
|
||||||
|
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||||
|
i := len(dAtA)
|
||||||
|
_ = i
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
{
|
||||||
|
size := m.MaxPriorityPrice.Size()
|
||||||
|
i -= size
|
||||||
|
if _, err := m.MaxPriorityPrice.MarshalTo(dAtA[i:]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
i = encodeVarintDynamicFee(dAtA, i, uint64(size))
|
||||||
|
}
|
||||||
|
i--
|
||||||
|
dAtA[i] = 0xa
|
||||||
|
return len(dAtA) - i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeVarintDynamicFee(dAtA []byte, offset int, v uint64) int {
|
||||||
|
offset -= sovDynamicFee(v)
|
||||||
|
base := offset
|
||||||
|
for v >= 1<<7 {
|
||||||
|
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||||
|
v >>= 7
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
dAtA[offset] = uint8(v)
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) Size() (n int) {
|
||||||
|
if m == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var l int
|
||||||
|
_ = l
|
||||||
|
l = m.MaxPriorityPrice.Size()
|
||||||
|
n += 1 + l + sovDynamicFee(uint64(l))
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func sovDynamicFee(x uint64) (n int) {
|
||||||
|
return (math_bits.Len64(x|1) + 6) / 7
|
||||||
|
}
|
||||||
|
func sozDynamicFee(x uint64) (n int) {
|
||||||
|
return sovDynamicFee(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||||
|
}
|
||||||
|
func (m *ExtensionOptionDynamicFeeTx) Unmarshal(dAtA []byte) error {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
preIndex := iNdEx
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowDynamicFee
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= uint64(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fieldNum := int32(wire >> 3)
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
if wireType == 4 {
|
||||||
|
return fmt.Errorf("proto: ExtensionOptionDynamicFeeTx: wiretype end group for non-group")
|
||||||
|
}
|
||||||
|
if fieldNum <= 0 {
|
||||||
|
return fmt.Errorf("proto: ExtensionOptionDynamicFeeTx: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||||
|
}
|
||||||
|
switch fieldNum {
|
||||||
|
case 1:
|
||||||
|
if wireType != 2 {
|
||||||
|
return fmt.Errorf("proto: wrong wireType = %d for field MaxPriorityPrice", wireType)
|
||||||
|
}
|
||||||
|
var stringLen uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return ErrIntOverflowDynamicFee
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
stringLen |= uint64(b&0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intStringLen := int(stringLen)
|
||||||
|
if intStringLen < 0 {
|
||||||
|
return ErrInvalidLengthDynamicFee
|
||||||
|
}
|
||||||
|
postIndex := iNdEx + intStringLen
|
||||||
|
if postIndex < 0 {
|
||||||
|
return ErrInvalidLengthDynamicFee
|
||||||
|
}
|
||||||
|
if postIndex > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
if err := m.MaxPriorityPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
iNdEx = postIndex
|
||||||
|
default:
|
||||||
|
iNdEx = preIndex
|
||||||
|
skippy, err := skipDynamicFee(dAtA[iNdEx:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||||
|
return ErrInvalidLengthDynamicFee
|
||||||
|
}
|
||||||
|
if (iNdEx + skippy) > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx += skippy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if iNdEx > l {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func skipDynamicFee(dAtA []byte) (n int, err error) {
|
||||||
|
l := len(dAtA)
|
||||||
|
iNdEx := 0
|
||||||
|
depth := 0
|
||||||
|
for iNdEx < l {
|
||||||
|
var wire uint64
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowDynamicFee
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
wire |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wireType := int(wire & 0x7)
|
||||||
|
switch wireType {
|
||||||
|
case 0:
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowDynamicFee
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
iNdEx++
|
||||||
|
if dAtA[iNdEx-1] < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
iNdEx += 8
|
||||||
|
case 2:
|
||||||
|
var length int
|
||||||
|
for shift := uint(0); ; shift += 7 {
|
||||||
|
if shift >= 64 {
|
||||||
|
return 0, ErrIntOverflowDynamicFee
|
||||||
|
}
|
||||||
|
if iNdEx >= l {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
b := dAtA[iNdEx]
|
||||||
|
iNdEx++
|
||||||
|
length |= (int(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if length < 0 {
|
||||||
|
return 0, ErrInvalidLengthDynamicFee
|
||||||
|
}
|
||||||
|
iNdEx += length
|
||||||
|
case 3:
|
||||||
|
depth++
|
||||||
|
case 4:
|
||||||
|
if depth == 0 {
|
||||||
|
return 0, ErrUnexpectedEndOfGroupDynamicFee
|
||||||
|
}
|
||||||
|
depth--
|
||||||
|
case 5:
|
||||||
|
iNdEx += 4
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||||
|
}
|
||||||
|
if iNdEx < 0 {
|
||||||
|
return 0, ErrInvalidLengthDynamicFee
|
||||||
|
}
|
||||||
|
if depth == 0 {
|
||||||
|
return iNdEx, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidLengthDynamicFee = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||||
|
ErrIntOverflowDynamicFee = fmt.Errorf("proto: integer overflow")
|
||||||
|
ErrUnexpectedEndOfGroupDynamicFee = fmt.Errorf("proto: unexpected end of group")
|
||||||
|
)
|
@ -15,11 +15,6 @@ import (
|
|||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultPriorityReduction is the default amount of price values required for 1 unit of priority.
|
|
||||||
// Because priority is `int64` while price is `big.Int`, it's necessary to scale down the range to keep it more pratical.
|
|
||||||
// The default value is the same as the `sdk.DefaultPowerReduction`.
|
|
||||||
var DefaultPriorityReduction = sdk.DefaultPowerReduction
|
|
||||||
|
|
||||||
// DeductTxCostsFromUserBalance it calculates the tx costs and deducts the fees
|
// DeductTxCostsFromUserBalance it calculates the tx costs and deducts the fees
|
||||||
// returns (effectiveFee, priority, error)
|
// returns (effectiveFee, priority, error)
|
||||||
func (k Keeper) DeductTxCostsFromUserBalance(
|
func (k Keeper) DeductTxCostsFromUserBalance(
|
||||||
@ -91,7 +86,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
|
|||||||
if baseFee != nil {
|
if baseFee != nil {
|
||||||
tipPrice = new(big.Int).Sub(tipPrice, baseFee)
|
tipPrice = new(big.Int).Sub(tipPrice, baseFee)
|
||||||
}
|
}
|
||||||
priorityBig := new(big.Int).Quo(tipPrice, DefaultPriorityReduction.BigInt())
|
priorityBig := new(big.Int).Quo(tipPrice, evmtypes.DefaultPriorityReduction.BigInt())
|
||||||
if !priorityBig.IsInt64() {
|
if !priorityBig.IsInt64() {
|
||||||
priority = math.MaxInt64
|
priority = math.MaxInt64
|
||||||
} else {
|
} else {
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
"github.com/evmos/ethermint/types"
|
"github.com/evmos/ethermint/types"
|
||||||
@ -267,7 +266,7 @@ func (tx DynamicFeeTx) Cost() *big.Int {
|
|||||||
|
|
||||||
// EffectiveGasPrice returns the effective gas price
|
// EffectiveGasPrice returns the effective gas price
|
||||||
func (tx *DynamicFeeTx) EffectiveGasPrice(baseFee *big.Int) *big.Int {
|
func (tx *DynamicFeeTx) EffectiveGasPrice(baseFee *big.Int) *big.Int {
|
||||||
return math.BigMin(new(big.Int).Add(tx.GasTipCap.BigInt(), baseFee), tx.GasFeeCap.BigInt())
|
return EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
// EffectiveFee returns effective_gasprice * gaslimit.
|
// EffectiveFee returns effective_gasprice * gaslimit.
|
||||||
|
2
x/evm/types/evm.pb.go
generated
2
x/evm/types/evm.pb.go
generated
@ -117,7 +117,7 @@ func (m *Params) GetAllowUnprotectedTxs() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainConfig defines the Ethereum ChainConfig parameters using *sdkmath.Int values
|
// ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int values
|
||||||
// instead of *big.Int.
|
// instead of *big.Int.
|
||||||
type ChainConfig struct {
|
type ChainConfig struct {
|
||||||
// Homestead switch block (nil no fork, 0 = already homestead)
|
// Homestead switch block (nil no fork, 0 = already homestead)
|
||||||
|
@ -2,6 +2,7 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
@ -9,9 +10,15 @@ import (
|
|||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DefaultPriorityReduction is the default amount of price values required for 1 unit of priority.
|
||||||
|
// Because priority is `int64` while price is `big.Int`, it's necessary to scale down the range to keep it more pratical.
|
||||||
|
// The default value is the same as the `sdk.DefaultPowerReduction`.
|
||||||
|
var DefaultPriorityReduction = sdk.DefaultPowerReduction
|
||||||
|
|
||||||
var EmptyCodeHash = crypto.Keccak256(nil)
|
var EmptyCodeHash = crypto.Keccak256(nil)
|
||||||
|
|
||||||
// DecodeTxResponse decodes an protobuf-encoded byte slice into TxResponse
|
// DecodeTxResponse decodes an protobuf-encoded byte slice into TxResponse
|
||||||
@ -88,3 +95,9 @@ func BinSearch(lo, hi uint64, executable func(uint64) (bool, *MsgEthereumTxRespo
|
|||||||
}
|
}
|
||||||
return hi, nil
|
return hi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EffectiveGasPrice compute the effective gas price based on eip-1159 rules
|
||||||
|
// `effectiveGasPrice = min(baseFee + tipCap, feeCap)`
|
||||||
|
func EffectiveGasPrice(baseFee *big.Int, feeCap *big.Int, tipCap *big.Int) *big.Int {
|
||||||
|
return math.BigMin(new(big.Int).Add(tipCap, baseFee), feeCap)
|
||||||
|
}
|
||||||
|
@ -126,7 +126,7 @@ var _ = Describe("Feemarket", func() {
|
|||||||
|
|
||||||
Context("with MinGasPrices (feemarket param) < min-gas-prices (local)", func() {
|
Context("with MinGasPrices (feemarket param) < min-gas-prices (local)", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
privKey, msg = setupTestWithContext("5", sdk.NewDec(3), sdk.ZeroInt())
|
privKey, msg = setupTestWithContext("5", sdk.NewDec(3), sdk.NewInt(5))
|
||||||
})
|
})
|
||||||
Context("during CheckTx", func() {
|
Context("during CheckTx", func() {
|
||||||
It("should reject transactions with gasPrice < MinGasPrices", func() {
|
It("should reject transactions with gasPrice < MinGasPrices", func() {
|
||||||
@ -139,7 +139,7 @@ var _ = Describe("Feemarket", func() {
|
|||||||
).To(BeTrue(), res.GetLog())
|
).To(BeTrue(), res.GetLog())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should reject transactions with MinGasPrices < gasPrice < min-gas-prices", func() {
|
It("should reject transactions with MinGasPrices < gasPrice < baseFee", func() {
|
||||||
gasPrice := sdkmath.NewInt(4)
|
gasPrice := sdkmath.NewInt(4)
|
||||||
res := checkTx(privKey, &gasPrice, &msg)
|
res := checkTx(privKey, &gasPrice, &msg)
|
||||||
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
||||||
@ -149,7 +149,7 @@ var _ = Describe("Feemarket", func() {
|
|||||||
).To(BeTrue(), res.GetLog())
|
).To(BeTrue(), res.GetLog())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should accept transactions with gasPrice > min-gas-prices", func() {
|
It("should accept transactions with gasPrice >= baseFee", func() {
|
||||||
gasPrice := sdkmath.NewInt(5)
|
gasPrice := sdkmath.NewInt(5)
|
||||||
res := checkTx(privKey, &gasPrice, &msg)
|
res := checkTx(privKey, &gasPrice, &msg)
|
||||||
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
||||||
@ -167,13 +167,16 @@ var _ = Describe("Feemarket", func() {
|
|||||||
).To(BeTrue(), res.GetLog())
|
).To(BeTrue(), res.GetLog())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should accept transactions with MinGasPrices < gasPrice < than min-gas-prices", func() {
|
It("should reject transactions with MinGasPrices < gasPrice < baseFee", func() {
|
||||||
gasPrice := sdkmath.NewInt(4)
|
gasPrice := sdkmath.NewInt(4)
|
||||||
res := deliverTx(privKey, &gasPrice, &msg)
|
res := checkTx(privKey, &gasPrice, &msg)
|
||||||
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
||||||
|
Expect(
|
||||||
|
strings.Contains(res.GetLog(),
|
||||||
|
"insufficient fee"),
|
||||||
|
).To(BeTrue(), res.GetLog())
|
||||||
})
|
})
|
||||||
|
It("should accept transactions with gasPrice >= baseFee", func() {
|
||||||
It("should accept transactions with gasPrice >= min-gas-prices", func() {
|
|
||||||
gasPrice := sdkmath.NewInt(5)
|
gasPrice := sdkmath.NewInt(5)
|
||||||
res := deliverTx(privKey, &gasPrice, &msg)
|
res := deliverTx(privKey, &gasPrice, &msg)
|
||||||
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
||||||
|
Loading…
Reference in New Issue
Block a user