e1560849dd
* Set priority for eth transactions Set the tx priority to the lowest priority in the messages. fix unit tests code cleanup and spec update spec fix go lint add priority integration test add python linter job add access list tx type fix gas limit remove ledger tag, so no need to replace hid dependency fix earlier check ibc-go v5.0.0-beta1 * fix pruned node integration test * Update x/feemarket/spec/09_antehandlers.md Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
675 lines
24 KiB
Go
675 lines
24 KiB
Go
package keeper_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"math/big"
|
|
"strings"
|
|
|
|
sdkmath "cosmossdk.io/math"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
|
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
|
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/evmos/ethermint/app"
|
|
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
|
"github.com/evmos/ethermint/encoding"
|
|
"github.com/evmos/ethermint/tests"
|
|
"github.com/evmos/ethermint/testutil"
|
|
"github.com/evmos/ethermint/x/feemarket/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/simapp"
|
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
dbm "github.com/tendermint/tm-db"
|
|
)
|
|
|
|
var _ = Describe("Feemarket", func() {
|
|
var (
|
|
privKey *ethsecp256k1.PrivKey
|
|
msg banktypes.MsgSend
|
|
)
|
|
|
|
Describe("Performing Cosmos transactions", func() {
|
|
Context("with min-gas-prices (local) < MinGasPrices (feemarket param)", func() {
|
|
BeforeEach(func() {
|
|
privKey, msg = setupTestWithContext("1", sdk.NewDec(3), sdk.ZeroInt())
|
|
})
|
|
|
|
Context("during CheckTx", func() {
|
|
It("should reject transactions with gasPrice < MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(2)
|
|
res := checkTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"provided fee < minimum global fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
})
|
|
|
|
It("should accept transactions with gasPrice >= MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(3)
|
|
res := checkTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
})
|
|
})
|
|
|
|
Context("during DeliverTx", func() {
|
|
It("should reject transactions with gasPrice < MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(2)
|
|
res := deliverTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"provided fee < minimum global fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
})
|
|
|
|
It("should accept transactions with gasPrice >= MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(3)
|
|
res := deliverTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("with min-gas-prices (local) == MinGasPrices (feemarket param)", func() {
|
|
BeforeEach(func() {
|
|
privKey, msg = setupTestWithContext("3", sdk.NewDec(3), sdk.ZeroInt())
|
|
})
|
|
|
|
Context("during CheckTx", func() {
|
|
It("should reject transactions with gasPrice < min-gas-prices", func() {
|
|
gasPrice := sdkmath.NewInt(2)
|
|
res := checkTx(privKey, &gasPrice, &msg)
|
|
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 >= MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(3)
|
|
res := checkTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
})
|
|
})
|
|
|
|
Context("during DeliverTx", func() {
|
|
It("should reject transactions with gasPrice < MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(2)
|
|
res := deliverTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"provided fee < minimum global fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
})
|
|
|
|
It("should accept transactions with gasPrice >= MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(3)
|
|
res := deliverTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
})
|
|
})
|
|
})
|
|
|
|
Context("with MinGasPrices (feemarket param) < min-gas-prices (local)", func() {
|
|
BeforeEach(func() {
|
|
privKey, msg = setupTestWithContext("5", sdk.NewDec(3), sdk.ZeroInt())
|
|
})
|
|
Context("during CheckTx", func() {
|
|
It("should reject transactions with gasPrice < MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(2)
|
|
res := checkTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"insufficient fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
})
|
|
|
|
It("should reject transactions with MinGasPrices < gasPrice < min-gas-prices", func() {
|
|
gasPrice := sdkmath.NewInt(4)
|
|
res := checkTx(privKey, &gasPrice, &msg)
|
|
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 > min-gas-prices", func() {
|
|
gasPrice := sdkmath.NewInt(5)
|
|
res := checkTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
})
|
|
})
|
|
|
|
Context("during DeliverTx", func() {
|
|
It("should reject transactions with gasPrice < MinGasPrices", func() {
|
|
gasPrice := sdkmath.NewInt(2)
|
|
res := deliverTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"provided fee < minimum global fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
})
|
|
|
|
It("should accept transactions with MinGasPrices < gasPrice < than min-gas-prices", func() {
|
|
gasPrice := sdkmath.NewInt(4)
|
|
res := deliverTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
})
|
|
|
|
It("should accept transactions with gasPrice >= min-gas-prices", func() {
|
|
gasPrice := sdkmath.NewInt(5)
|
|
res := deliverTx(privKey, &gasPrice, &msg)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Performing EVM transactions", func() {
|
|
type txParams struct {
|
|
gasPrice *big.Int
|
|
gasFeeCap *big.Int
|
|
gasTipCap *big.Int
|
|
accesses *ethtypes.AccessList
|
|
}
|
|
type getprices func() txParams
|
|
|
|
Context("with BaseFee (feemarket) < MinGasPrices (feemarket param)", func() {
|
|
var (
|
|
baseFee int64
|
|
minGasPrices int64
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
baseFee = 10_000_000_000
|
|
minGasPrices = baseFee + 30_000_000_000
|
|
|
|
// Note that the tests run the same transactions with `gasLimit =
|
|
// 100000`. With the fee calculation `Fee = (baseFee + tip) * gasLimit`,
|
|
// a `minGasPrices = 40_000_000_000` results in `minGlobalFee =
|
|
// 4000000000000000`
|
|
privKey, _ = setupTestWithContext("1", sdk.NewDec(minGasPrices), sdkmath.NewInt(baseFee))
|
|
})
|
|
|
|
Context("during CheckTx", func() {
|
|
DescribeTable("should reject transactions with EffectivePrice < MinGasPrices",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := checkEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"provided fee < minimum global fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(minGasPrices - 10_000_000_000), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx with GasFeeCap < MinGasPrices, no gasTipCap", func() txParams {
|
|
return txParams{nil, big.NewInt(minGasPrices - 10_000_000_000), big.NewInt(0), ðtypes.AccessList{}}
|
|
}),
|
|
Entry("dynamic tx with GasFeeCap < MinGasPrices, max gasTipCap", func() txParams {
|
|
// Note that max priority fee per gas can't be higher than the max fee per gas (gasFeeCap), i.e. 30_000_000_000)
|
|
return txParams{nil, big.NewInt(minGasPrices - 10_000_000_000), big.NewInt(30_000_000_000), ðtypes.AccessList{}}
|
|
}),
|
|
Entry("dynamic tx with GasFeeCap > MinGasPrices, EffectivePrice < MinGasPrices", func() txParams {
|
|
return txParams{nil, big.NewInt(minGasPrices + 10_000_000_000), big.NewInt(0), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
|
|
DescribeTable("should accept transactions with gasPrice >= MinGasPrices",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := checkEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(minGasPrices), nil, nil, nil}
|
|
}),
|
|
// Note that this tx is not rejected on CheckTx, but not on DeliverTx,
|
|
// as the baseFee is set to minGasPrices during DeliverTx when baseFee
|
|
// < minGasPrices
|
|
Entry("dynamic tx with GasFeeCap > MinGasPrices, EffectivePrice > MinGasPrices", func() txParams {
|
|
return txParams{nil, big.NewInt(minGasPrices), big.NewInt(30_000_000_000), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
})
|
|
|
|
Context("during DeliverTx", func() {
|
|
DescribeTable("should reject transactions with gasPrice < MinGasPrices",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := deliverEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"provided fee < minimum global fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(minGasPrices - 10_000_000_000), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx with GasFeeCap < MinGasPrices, no gasTipCap", func() txParams {
|
|
return txParams{nil, big.NewInt(minGasPrices - 10_000_000_000), big.NewInt(0), ðtypes.AccessList{}}
|
|
}),
|
|
Entry("dynamic tx with GasFeeCap < MinGasPrices, max gasTipCap", func() txParams {
|
|
// Note that max priority fee per gas can't be higher than the max fee per gas (gasFeeCap), i.e. 30_000_000_000)
|
|
return txParams{nil, big.NewInt(minGasPrices - 10_000_000_000), big.NewInt(30_000_000_000), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
|
|
DescribeTable("should accept transactions with gasPrice >= MinGasPrices",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := deliverEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(minGasPrices + 1), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx, EffectivePrice > MinGasPrices", func() txParams {
|
|
return txParams{nil, big.NewInt(minGasPrices + 10_000_000_000), big.NewInt(30_000_000_000), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
})
|
|
})
|
|
|
|
Context("with MinGasPrices (feemarket param) < BaseFee (feemarket)", func() {
|
|
var (
|
|
baseFee int64
|
|
minGasPrices int64
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
baseFee = 10_000_000_000
|
|
minGasPrices = baseFee - 5_000_000_000
|
|
|
|
// Note that the tests run the same transactions with `gasLimit =
|
|
// 100_000`. With the fee calculation `Fee = (baseFee + tip) * gasLimit`,
|
|
// a `minGasPrices = 5_000_000_000` results in `minGlobalFee =
|
|
// 500_000_000_000_000`
|
|
privKey, _ = setupTestWithContext("1", sdk.NewDec(minGasPrices), sdkmath.NewInt(baseFee))
|
|
})
|
|
|
|
Context("during CheckTx", func() {
|
|
DescribeTable("should reject transactions with gasPrice < MinGasPrices",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := checkEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"provided fee < minimum global fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(minGasPrices - 1_000_000_000), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx with GasFeeCap < MinGasPrices, no gasTipCap", func() txParams {
|
|
return txParams{nil, big.NewInt(minGasPrices - 1_000_000_000), big.NewInt(0), ðtypes.AccessList{}}
|
|
}),
|
|
Entry("dynamic tx with GasFeeCap < MinGasPrices, max gasTipCap", func() txParams {
|
|
return txParams{nil, big.NewInt(minGasPrices - 1_000_000_000), big.NewInt(minGasPrices - 1_000_000_000), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
|
|
DescribeTable("should reject transactions with MinGasPrices < tx gasPrice < EffectivePrice",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := checkEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"insufficient fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(baseFee - 1_000_000_000), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx", func() txParams {
|
|
return txParams{nil, big.NewInt(baseFee - 1_000_000_000), big.NewInt(0), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
|
|
DescribeTable("should accept transactions with gasPrice >= EffectivePrice",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := checkEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(baseFee), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx", func() txParams {
|
|
return txParams{nil, big.NewInt(baseFee), big.NewInt(0), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
})
|
|
|
|
Context("during DeliverTx", func() {
|
|
DescribeTable("should reject transactions with gasPrice < MinGasPrices",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := deliverEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"provided fee < minimum global fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(minGasPrices - 1_000_000_000), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx", func() txParams {
|
|
return txParams{nil, big.NewInt(minGasPrices - 1_000_000_000), nil, ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
|
|
DescribeTable("should reject transactions with MinGasPrices < gasPrice < EffectivePrice",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := deliverEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(false), "transaction should have failed")
|
|
Expect(
|
|
strings.Contains(res.GetLog(),
|
|
"insufficient fee"),
|
|
).To(BeTrue(), res.GetLog())
|
|
},
|
|
// Note that the baseFee is not 10_000_000_000 anymore but updates to 8_750_000_000 because of the s.Commit
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(baseFee - 2_000_000_000), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx", func() txParams {
|
|
return txParams{nil, big.NewInt(baseFee - 2_000_000_000), big.NewInt(0), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
|
|
DescribeTable("should accept transactions with gasPrice >= EffectivePrice",
|
|
func(malleate getprices) {
|
|
p := malleate()
|
|
to := tests.GenerateAddress()
|
|
msgEthereumTx := buildEthTx(privKey, &to, p.gasPrice, p.gasFeeCap, p.gasTipCap, p.accesses)
|
|
res := deliverEthTx(privKey, msgEthereumTx)
|
|
Expect(res.IsOK()).To(Equal(true), "transaction should have succeeded", res.GetLog())
|
|
},
|
|
Entry("legacy tx", func() txParams {
|
|
return txParams{big.NewInt(baseFee), nil, nil, nil}
|
|
}),
|
|
Entry("dynamic tx", func() txParams {
|
|
return txParams{nil, big.NewInt(baseFee), big.NewInt(0), ðtypes.AccessList{}}
|
|
}),
|
|
)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
// setupTestWithContext sets up a test chain with an example Cosmos send msg,
|
|
// given a local (validator config) and a gloabl (feemarket param) minGasPrice
|
|
func setupTestWithContext(valMinGasPrice string, minGasPrice sdk.Dec, baseFee sdkmath.Int) (*ethsecp256k1.PrivKey, banktypes.MsgSend) {
|
|
privKey, msg := setupTest(valMinGasPrice + s.denom)
|
|
params := types.DefaultParams()
|
|
params.MinGasPrice = minGasPrice
|
|
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
|
s.app.FeeMarketKeeper.SetBaseFee(s.ctx, baseFee.BigInt())
|
|
s.Commit()
|
|
|
|
return privKey, msg
|
|
}
|
|
|
|
func setupTest(localMinGasPrices string) (*ethsecp256k1.PrivKey, banktypes.MsgSend) {
|
|
setupChain(localMinGasPrices)
|
|
|
|
privKey, address := generateKey()
|
|
amount, ok := sdkmath.NewIntFromString("10000000000000000000")
|
|
s.Require().True(ok)
|
|
initBalance := sdk.Coins{sdk.Coin{
|
|
Denom: s.denom,
|
|
Amount: amount,
|
|
}}
|
|
testutil.FundAccount(s.app.BankKeeper, s.ctx, address, initBalance)
|
|
|
|
msg := banktypes.MsgSend{
|
|
FromAddress: address.String(),
|
|
ToAddress: address.String(),
|
|
Amount: sdk.Coins{sdk.Coin{
|
|
Denom: s.denom,
|
|
Amount: sdkmath.NewInt(10000),
|
|
}},
|
|
}
|
|
s.Commit()
|
|
return privKey, msg
|
|
}
|
|
|
|
func setupChain(localMinGasPricesStr string) {
|
|
// Initialize the app, so we can use SetMinGasPrices to set the
|
|
// validator-specific min-gas-prices setting
|
|
db := dbm.NewMemDB()
|
|
newapp := app.NewEthermintApp(
|
|
log.NewNopLogger(),
|
|
db,
|
|
nil,
|
|
true,
|
|
map[int64]bool{},
|
|
app.DefaultNodeHome,
|
|
5,
|
|
encoding.MakeConfig(app.ModuleBasics),
|
|
simapp.EmptyAppOptions{},
|
|
baseapp.SetMinGasPrices(localMinGasPricesStr),
|
|
)
|
|
|
|
genesisState := app.NewTestGenesisState(newapp.AppCodec())
|
|
genesisState[types.ModuleName] = newapp.AppCodec().MustMarshalJSON(types.DefaultGenesisState())
|
|
|
|
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
|
s.Require().NoError(err)
|
|
|
|
// Initialize the chain
|
|
newapp.InitChain(
|
|
abci.RequestInitChain{
|
|
ChainId: "ethermint_9000-1",
|
|
Validators: []abci.ValidatorUpdate{},
|
|
AppStateBytes: stateBytes,
|
|
ConsensusParams: app.DefaultConsensusParams,
|
|
},
|
|
)
|
|
|
|
s.app = newapp
|
|
s.SetupApp(false)
|
|
}
|
|
|
|
func generateKey() (*ethsecp256k1.PrivKey, sdk.AccAddress) {
|
|
address, priv := tests.NewAddrKey()
|
|
return priv.(*ethsecp256k1.PrivKey), sdk.AccAddress(address.Bytes())
|
|
}
|
|
|
|
func getNonce(addressBytes []byte) uint64 {
|
|
return s.app.EvmKeeper.GetNonce(
|
|
s.ctx,
|
|
common.BytesToAddress(addressBytes),
|
|
)
|
|
}
|
|
|
|
func buildEthTx(
|
|
priv *ethsecp256k1.PrivKey,
|
|
to *common.Address,
|
|
gasPrice *big.Int,
|
|
gasFeeCap *big.Int,
|
|
gasTipCap *big.Int,
|
|
accesses *ethtypes.AccessList,
|
|
) *evmtypes.MsgEthereumTx {
|
|
chainID := s.app.EvmKeeper.ChainID()
|
|
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
|
|
nonce := getNonce(from.Bytes())
|
|
data := make([]byte, 0)
|
|
gasLimit := uint64(100000)
|
|
msgEthereumTx := evmtypes.NewTx(
|
|
chainID,
|
|
nonce,
|
|
to,
|
|
nil,
|
|
gasLimit,
|
|
gasPrice,
|
|
gasFeeCap,
|
|
gasTipCap,
|
|
data,
|
|
accesses,
|
|
)
|
|
msgEthereumTx.From = from.String()
|
|
return msgEthereumTx
|
|
}
|
|
|
|
func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) []byte {
|
|
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
|
option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
|
|
s.Require().NoError(err)
|
|
|
|
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
|
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
|
|
s.Require().True(ok)
|
|
builder.SetExtensionOptions(option)
|
|
|
|
err = msgEthereumTx.Sign(s.ethSigner, tests.NewSigner(priv))
|
|
s.Require().NoError(err)
|
|
|
|
msgEthereumTx.From = ""
|
|
err = txBuilder.SetMsgs(msgEthereumTx)
|
|
s.Require().NoError(err)
|
|
|
|
txData, err := evmtypes.UnpackTxData(msgEthereumTx.Data)
|
|
s.Require().NoError(err)
|
|
|
|
evmDenom := s.app.EvmKeeper.GetParams(s.ctx).EvmDenom
|
|
fees := sdk.Coins{{Denom: evmDenom, Amount: sdkmath.NewIntFromBigInt(txData.Fee())}}
|
|
builder.SetFeeAmount(fees)
|
|
builder.SetGasLimit(msgEthereumTx.GetGas())
|
|
|
|
// bz are bytes to be broadcasted over the network
|
|
bz, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
|
|
s.Require().NoError(err)
|
|
|
|
return bz
|
|
}
|
|
|
|
func checkEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) abci.ResponseCheckTx {
|
|
bz := prepareEthTx(priv, msgEthereumTx)
|
|
req := abci.RequestCheckTx{Tx: bz}
|
|
res := s.app.BaseApp.CheckTx(req)
|
|
return res
|
|
}
|
|
|
|
func deliverEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereumTx) abci.ResponseDeliverTx {
|
|
bz := prepareEthTx(priv, msgEthereumTx)
|
|
req := abci.RequestDeliverTx{Tx: bz}
|
|
res := s.app.BaseApp.DeliverTx(req)
|
|
return res
|
|
}
|
|
|
|
func prepareCosmosTx(priv *ethsecp256k1.PrivKey, gasPrice *sdkmath.Int, msgs ...sdk.Msg) []byte {
|
|
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
|
accountAddress := sdk.AccAddress(priv.PubKey().Address().Bytes())
|
|
|
|
txBuilder := encodingConfig.TxConfig.NewTxBuilder()
|
|
|
|
txBuilder.SetGasLimit(1000000)
|
|
if gasPrice == nil {
|
|
_gasPrice := sdkmath.NewInt(1)
|
|
gasPrice = &_gasPrice
|
|
}
|
|
fees := &sdk.Coins{{Denom: s.denom, Amount: gasPrice.MulRaw(1000000)}}
|
|
txBuilder.SetFeeAmount(*fees)
|
|
err := txBuilder.SetMsgs(msgs...)
|
|
s.Require().NoError(err)
|
|
|
|
seq, err := s.app.AccountKeeper.GetSequence(s.ctx, accountAddress)
|
|
s.Require().NoError(err)
|
|
|
|
// First round: we gather all the signer infos. We use the "set empty
|
|
// signature" hack to do that.
|
|
sigV2 := signing.SignatureV2{
|
|
PubKey: priv.PubKey(),
|
|
Data: &signing.SingleSignatureData{
|
|
SignMode: encodingConfig.TxConfig.SignModeHandler().DefaultMode(),
|
|
Signature: nil,
|
|
},
|
|
Sequence: seq,
|
|
}
|
|
|
|
sigsV2 := []signing.SignatureV2{sigV2}
|
|
|
|
err = txBuilder.SetSignatures(sigsV2...)
|
|
s.Require().NoError(err)
|
|
|
|
// Second round: all signer infos are set, so each signer can sign.
|
|
accNumber := s.app.AccountKeeper.GetAccount(s.ctx, accountAddress).GetAccountNumber()
|
|
signerData := authsigning.SignerData{
|
|
ChainID: s.ctx.ChainID(),
|
|
AccountNumber: accNumber,
|
|
Sequence: seq,
|
|
}
|
|
sigV2, err = tx.SignWithPrivKey(
|
|
encodingConfig.TxConfig.SignModeHandler().DefaultMode(), signerData,
|
|
txBuilder, priv, encodingConfig.TxConfig,
|
|
seq,
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
sigsV2 = []signing.SignatureV2{sigV2}
|
|
err = txBuilder.SetSignatures(sigsV2...)
|
|
s.Require().NoError(err)
|
|
|
|
// bz are bytes to be broadcasted over the network
|
|
bz, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx())
|
|
s.Require().NoError(err)
|
|
return bz
|
|
}
|
|
|
|
func checkTx(priv *ethsecp256k1.PrivKey, gasPrice *sdkmath.Int, msgs ...sdk.Msg) abci.ResponseCheckTx {
|
|
bz := prepareCosmosTx(priv, gasPrice, msgs...)
|
|
req := abci.RequestCheckTx{Tx: bz}
|
|
res := s.app.BaseApp.CheckTx(req)
|
|
return res
|
|
}
|
|
|
|
func deliverTx(priv *ethsecp256k1.PrivKey, gasPrice *sdkmath.Int, msgs ...sdk.Msg) abci.ResponseDeliverTx {
|
|
bz := prepareCosmosTx(priv, gasPrice, msgs...)
|
|
req := abci.RequestDeliverTx{Tx: bz}
|
|
res := s.app.BaseApp.DeliverTx(req)
|
|
return res
|
|
}
|