forked from cerc-io/laconicd-deprecated
update fork
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
cmdcfg "github.com/cerc-io/laconicd/cmd/config"
|
||||
)
|
||||
|
||||
// sdk config
|
||||
func init() {
|
||||
config := sdk.GetConfig()
|
||||
cmdcfg.SetBech32Prefixes(config)
|
||||
cmdcfg.SetBip44CoinType(config)
|
||||
config.Seal()
|
||||
|
||||
cmdcfg.RegisterDenoms()
|
||||
}
|
||||
+9
-2
@@ -23,7 +23,11 @@ const (
|
||||
// Ethereum or SDK transaction to an internal ante handler for performing
|
||||
// transaction-level processing (e.g. fee payment, signature verification) before
|
||||
// being passed onto it's respective handler.
|
||||
func NewAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
||||
if err := options.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return func(
|
||||
ctx sdk.Context, tx sdk.Tx, sim bool,
|
||||
) (newCtx sdk.Context, err error) {
|
||||
@@ -42,6 +46,9 @@ func NewAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||
anteHandler = newCosmosAnteHandlerEip712(options)
|
||||
case "/ethermint.types.v1.ExtensionOptionDynamicFeeTx":
|
||||
// cosmos-sdk tx with dynamic fee extension
|
||||
anteHandler = newCosmosAnteHandler(options)
|
||||
default:
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrUnknownExtensionOptions,
|
||||
@@ -62,7 +69,7 @@ func NewAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
}
|
||||
|
||||
return anteHandler(ctx, tx, sim)
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func Recover(logger tmlog.Logger, err *error) {
|
||||
|
||||
+380
-152
@@ -1,10 +1,16 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
@@ -12,22 +18,27 @@ import (
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
ethparams "github.com/ethereum/go-ethereum/params"
|
||||
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
)
|
||||
|
||||
func (suite AnteTestSuite) TestAnteHandler() {
|
||||
suite.enableFeemarket = false
|
||||
suite.SetupTest() // reset
|
||||
|
||||
var acc authtypes.AccountI
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
to := tests.GenerateAddress()
|
||||
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.Require().NoError(acc.SetSequence(1))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
setup := func() {
|
||||
suite.enableFeemarket = false
|
||||
suite.SetupTest() // reset
|
||||
|
||||
suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt(10000000000))
|
||||
acc = suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.Require().NoError(acc.SetSequence(1))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, big.NewInt(100))
|
||||
suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt(10000000000))
|
||||
|
||||
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, big.NewInt(100))
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
@@ -62,7 +73,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
func() sdk.Tx {
|
||||
signedContractTx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
2,
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
big.NewInt(150),
|
||||
@@ -83,7 +94,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
func() sdk.Tx {
|
||||
signedContractTx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
3,
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
big.NewInt(150),
|
||||
@@ -104,7 +115,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
4,
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
@@ -126,7 +137,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
5,
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
@@ -148,7 +159,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
6,
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
@@ -169,7 +180,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
7,
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
@@ -188,7 +199,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
{
|
||||
"fail - CheckTx (cosmos tx is not valid)",
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 8, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||
@@ -200,7 +211,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
{
|
||||
"fail - CheckTx (memo too long)",
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 5, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||
@@ -211,7 +222,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
{
|
||||
"fail - CheckTx (ExtensionOptionsEthereumTx not set)",
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 5, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false, true)
|
||||
@@ -273,7 +284,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
|
||||
expFee := txData.Fee()
|
||||
invalidFee := new(big.Int).Add(expFee, big.NewInt(1))
|
||||
invalidFeeAmount := sdk.Coins{sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewIntFromBigInt(invalidFee))}
|
||||
invalidFeeAmount := sdk.Coins{sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewIntFromBigInt(invalidFee))}
|
||||
txBuilder.SetFeeAmount(invalidFeeAmount)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, false,
|
||||
@@ -298,20 +309,95 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
"success - DeliverTx EIP712 signed Cosmos Tx with MsgSend",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
|
||||
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)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
{
|
||||
"success - DeliverTx EIP712 signed Cosmos Tx with DelegateMsg",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
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)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
{
|
||||
"success- DeliverTx EIP712 create validator",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
amount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
txBuilder := suite.CreateTestEIP712TxBuilderMsgDelegate(from, privKey, "ethermint_9000-1", gas, amount)
|
||||
txBuilder := suite.CreateTestEIP712MsgCreateValidator(from, privKey, "ethermint_9000-1", gas, amount)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
{
|
||||
"success- DeliverTx EIP712 MsgSubmitProposal",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
gasAmount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
//reusing the gasAmount for deposit
|
||||
deposit := sdk.NewCoins(coinAmount)
|
||||
txBuilder := suite.CreateTestEIP712SubmitProposal(from, privKey, "ethermint_9000-1", gas, gasAmount, deposit)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
{
|
||||
"success- DeliverTx EIP712 MsgGrant",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
grantee := sdk.AccAddress("_______grantee______")
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
gasAmount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
blockTime := time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)
|
||||
expiresAt := blockTime.Add(time.Hour)
|
||||
msg, err := authz.NewMsgGrant(
|
||||
from, grantee, &banktypes.SendAuthorization{SpendLimit: gasAmount}, &expiresAt,
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, privKey, "ethermint_9000-1", gas, gasAmount, msg).GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
|
||||
{
|
||||
"success- DeliverTx EIP712 MsgGrantAllowance",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
gasAmount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
txBuilder := suite.CreateTestEIP712GrantAllowance(from, privKey, "ethermint_9000-1", gas, gasAmount)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
{
|
||||
"success- DeliverTx EIP712 edit validator",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
amount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
txBuilder := suite.CreateTestEIP712MsgEditValidator(from, privKey, "ethermint_9000-1", gas, amount)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
{
|
||||
"success- DeliverTx EIP712 submit evidence",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
|
||||
amount := sdk.NewCoins(coinAmount)
|
||||
gas := uint64(200000)
|
||||
txBuilder := suite.CreateTestEIP712MsgEditValidator(from, privKey, "ethermint_9000-1", gas, amount)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, true,
|
||||
},
|
||||
@@ -319,8 +405,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
"fails - DeliverTx EIP712 signed Cosmos Tx with wrong Chain ID",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
|
||||
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)
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, false,
|
||||
@@ -329,11 +415,11 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
"fails - DeliverTx EIP712 signed Cosmos Tx with different gas fees",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
|
||||
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.SetGasLimit(uint64(300000))
|
||||
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(30))))
|
||||
txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(30))))
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, false,
|
||||
},
|
||||
@@ -341,8 +427,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
"fails - DeliverTx EIP712 signed Cosmos Tx with empty signature",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
|
||||
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)
|
||||
sigsV2 := signing.SignatureV2{}
|
||||
txBuilder.SetSignatures(sigsV2)
|
||||
@@ -353,8 +439,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid sequence",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
|
||||
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)
|
||||
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
@@ -373,8 +459,8 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid signMode",
|
||||
func() sdk.Tx {
|
||||
from := acc.GetAddress()
|
||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
|
||||
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)
|
||||
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
@@ -389,10 +475,33 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
return txBuilder.GetTx()
|
||||
}, false, false, false,
|
||||
},
|
||||
{
|
||||
"fails - invalid from",
|
||||
func() sdk.Tx {
|
||||
msg := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
big.NewInt(150),
|
||||
big.NewInt(200),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
msg.From = addr.Hex()
|
||||
tx := suite.CreateTestTx(msg, privKey, 1, false)
|
||||
msg = tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
msg.From = addr.Hex()
|
||||
return tx
|
||||
}, true, false, false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
setup()
|
||||
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx)
|
||||
|
||||
// expConsumed := params.TxGasContractCreation + params.TxGas
|
||||
@@ -425,18 +534,17 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"success - DeliverTx (contract)",
|
||||
func() sdk.Tx {
|
||||
signedContractTx :=
|
||||
evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||
@@ -448,18 +556,17 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"success - CheckTx (contract)",
|
||||
func() sdk.Tx {
|
||||
signedContractTx :=
|
||||
evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||
@@ -471,18 +578,17 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"success - ReCheckTx (contract)",
|
||||
func() sdk.Tx {
|
||||
signedContractTx :=
|
||||
evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||
@@ -494,19 +600,18 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"success - DeliverTx",
|
||||
func() sdk.Tx {
|
||||
signedTx :=
|
||||
evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||
@@ -518,19 +623,18 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"success - CheckTx",
|
||||
func() sdk.Tx {
|
||||
signedTx :=
|
||||
evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||
@@ -542,19 +646,18 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"success - ReCheckTx",
|
||||
func() sdk.Tx {
|
||||
signedTx :=
|
||||
evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||
@@ -566,19 +669,18 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"success - CheckTx (cosmos tx not signed)",
|
||||
func() sdk.Tx {
|
||||
signedTx :=
|
||||
evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||
@@ -590,19 +692,18 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"fail - CheckTx (cosmos tx is not valid)",
|
||||
func() sdk.Tx {
|
||||
signedTx :=
|
||||
evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||
@@ -616,19 +717,18 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"fail - CheckTx (memo too long)",
|
||||
func() sdk.Tx {
|
||||
signedTx :=
|
||||
evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||
@@ -641,18 +741,17 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
{
|
||||
"fail - DynamicFeeTx without london hark fork",
|
||||
func() sdk.Tx {
|
||||
signedContractTx :=
|
||||
evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||
@@ -686,3 +785,132 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
suite.enableFeemarket = false
|
||||
suite.enableLondonHF = true
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestAnteHandlerWithParams() {
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
to := tests.GenerateAddress()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
txFn func() sdk.Tx
|
||||
enableCall bool
|
||||
enableCreate bool
|
||||
expErr error
|
||||
}{
|
||||
{
|
||||
"fail - Contract Creation Disabled",
|
||||
func() sdk.Tx {
|
||||
signedContractTx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||
return tx
|
||||
},
|
||||
true, false,
|
||||
evmtypes.ErrCreateDisabled,
|
||||
},
|
||||
{
|
||||
"success - Contract Creation Enabled",
|
||||
func() sdk.Tx {
|
||||
signedContractTx := evmtypes.NewTxContract(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedContractTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||
return tx
|
||||
},
|
||||
true, true,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"fail - EVM Call Disabled",
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||
return tx
|
||||
},
|
||||
false, true,
|
||||
evmtypes.ErrCallDisabled,
|
||||
},
|
||||
{
|
||||
"success - EVM Call Enabled",
|
||||
func() sdk.Tx {
|
||||
signedTx := evmtypes.NewTx(
|
||||
suite.app.EvmKeeper.ChainID(),
|
||||
1,
|
||||
&to,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
nil,
|
||||
big.NewInt(ethparams.InitialBaseFee+1),
|
||||
big.NewInt(1),
|
||||
nil,
|
||||
&types.AccessList{},
|
||||
)
|
||||
signedTx.From = addr.Hex()
|
||||
|
||||
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||
return tx
|
||||
},
|
||||
true, true,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.evmParamsOption = func(params *evmtypes.Params) {
|
||||
params.EnableCall = tc.enableCall
|
||||
params.EnableCreate = tc.enableCreate
|
||||
}
|
||||
suite.SetupTest() // reset
|
||||
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||
suite.Require().NoError(acc.SetSequence(1))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(true)
|
||||
suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt((ethparams.InitialBaseFee+10)*100000))
|
||||
_, err := suite.anteHandler(suite.ctx, tc.txFn(), false)
|
||||
if tc.expErr == nil {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
suite.Require().True(errors.Is(err, tc.expErr))
|
||||
}
|
||||
})
|
||||
}
|
||||
suite.evmParamsOption = nil
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
/*Package ante defines the SDK auth module's AnteHandler as well as an internal
|
||||
/*
|
||||
Package ante defines the SDK auth module's AnteHandler as well as an internal
|
||||
AnteHandler for an Ethereum transaction (i.e MsgEthereumTx).
|
||||
|
||||
During CheckTx, the transaction is passed through a series of
|
||||
|
||||
+6
-8
@@ -49,7 +49,11 @@ func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandle
|
||||
|
||||
// AnteHandle handles validation of EIP712 signed cosmos txs.
|
||||
// it is not run on RecheckTx
|
||||
func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context,
|
||||
tx sdk.Tx,
|
||||
simulate bool,
|
||||
next sdk.AnteHandler,
|
||||
) (newCtx sdk.Context, err error) {
|
||||
// no need to verify signatures on recheck tx
|
||||
if ctx.IsReCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
@@ -188,13 +192,7 @@ func VerifySignature(
|
||||
return sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, "tx doesnt contain expected amount of extension options")
|
||||
}
|
||||
|
||||
var optIface ethermint.ExtensionOptionsWeb3TxI
|
||||
|
||||
if err := ethermintCodec.UnpackAny(opts[0], &optIface); err != nil {
|
||||
return sdkerrors.Wrap(err, "failed to proto-unpack ExtensionOptionsWeb3Tx")
|
||||
}
|
||||
|
||||
extOpt, ok := optIface.(*ethermint.ExtensionOptionsWeb3Tx)
|
||||
extOpt, ok := opts[0].GetCachedValue().(*ethermint.ExtensionOptionsWeb3Tx)
|
||||
if !ok {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidChainID, "unknown extension option")
|
||||
}
|
||||
|
||||
+136
-66
@@ -2,7 +2,11 @@ package ante
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
@@ -49,12 +53,18 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
sender, err := signer.Sender(msgEthTx.AsTransaction())
|
||||
ethTx := msgEthTx.AsTransaction()
|
||||
if !params.AllowUnprotectedTxs && !ethTx.Protected() {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrNotSupported,
|
||||
"rejected unprotected Ethereum txs. Please EIP155 sign your transaction to protect it against replay-attacks")
|
||||
}
|
||||
|
||||
sender, err := signer.Sender(ethTx)
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrorInvalidSigner,
|
||||
"couldn't retrieve sender address ('%s') from the ethereum transaction: %s",
|
||||
msgEthTx.From,
|
||||
"couldn't retrieve sender address from the ethereum transaction: %s",
|
||||
err.Error(),
|
||||
)
|
||||
}
|
||||
@@ -68,17 +78,15 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
|
||||
|
||||
// EthAccountVerificationDecorator validates an account balance checks
|
||||
type EthAccountVerificationDecorator struct {
|
||||
ak evmtypes.AccountKeeper
|
||||
bankKeeper evmtypes.BankKeeper
|
||||
evmKeeper EVMKeeper
|
||||
ak evmtypes.AccountKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator
|
||||
func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, bankKeeper evmtypes.BankKeeper, ek EVMKeeper) EthAccountVerificationDecorator {
|
||||
func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, ek EVMKeeper) EthAccountVerificationDecorator {
|
||||
return EthAccountVerificationDecorator{
|
||||
ak: ak,
|
||||
bankKeeper: bankKeeper,
|
||||
evmKeeper: ek,
|
||||
ak: ak,
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +96,12 @@ func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, bankKeeper ev
|
||||
// - any of the msgs is not a MsgEthereumTx
|
||||
// - from address is empty
|
||||
// - account balance is lower than the transaction cost
|
||||
func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
func (avd EthAccountVerificationDecorator) AnteHandle(
|
||||
ctx sdk.Context,
|
||||
tx sdk.Tx,
|
||||
simulate bool,
|
||||
next sdk.AnteHandler,
|
||||
) (newCtx sdk.Context, err error) {
|
||||
if !ctx.IsCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
@@ -123,10 +136,9 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx
|
||||
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
|
||||
}
|
||||
|
||||
if err := evmkeeper.CheckSenderBalance(sdk.NewIntFromBigInt(acct.Balance), txData); err != nil {
|
||||
if err := evmkeeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil {
|
||||
return ctx, sdkerrors.Wrap(err, "failed to check sender balance")
|
||||
}
|
||||
|
||||
}
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
@@ -163,7 +175,7 @@ func NewEthGasConsumeDecorator(
|
||||
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
|
||||
// - transaction or block gas meter runs out of gas
|
||||
// - sets the gas meter limit
|
||||
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
params := egcd.evmKeeper.GetParams(ctx)
|
||||
|
||||
ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
|
||||
@@ -176,6 +188,9 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
gasWanted := uint64(0)
|
||||
var events sdk.Events
|
||||
|
||||
// Use the lowest priority of all the messages as the final one.
|
||||
minPriority := int64(math.MaxInt64)
|
||||
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
@@ -187,7 +202,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
|
||||
}
|
||||
|
||||
if ctx.IsCheckTx() {
|
||||
if ctx.IsCheckTx() && egcd.maxGasWanted != 0 {
|
||||
// We can't trust the tx gas limit, because we'll refund the unused gas.
|
||||
if txData.GetGas() > egcd.maxGasWanted {
|
||||
gasWanted += egcd.maxGasWanted
|
||||
@@ -198,7 +213,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
gasWanted += txData.GetGas()
|
||||
}
|
||||
|
||||
fees, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
|
||||
fees, priority, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
|
||||
ctx,
|
||||
*msgEthTx,
|
||||
txData,
|
||||
@@ -212,6 +227,9 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
}
|
||||
|
||||
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
|
||||
if priority < minPriority {
|
||||
minPriority = priority
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: change to typed events
|
||||
@@ -233,8 +251,10 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
ctx = ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
|
||||
ctx.GasMeter().ConsumeGas(gasConsumed, "copy gas consumed")
|
||||
|
||||
newCtx := ctx.WithPriority(minPriority)
|
||||
|
||||
// we know that we have enough gas on the pool to cover the intrinsic gas
|
||||
return next(ctx, tx, simulate)
|
||||
return next(newCtx, tx, simulate)
|
||||
}
|
||||
|
||||
// CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block
|
||||
@@ -263,7 +283,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
baseFee := ctd.evmKeeper.BaseFee(ctx, ethCfg)
|
||||
baseFee := ctd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
|
||||
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
|
||||
if err != nil {
|
||||
@@ -285,7 +305,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
|
||||
|
||||
// check that caller has enough balance to cover asset transfer for **topmost** call
|
||||
// NOTE: here the gas consumed is from the context with the infinite gas meter
|
||||
if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
|
||||
if coreMsg.Value().Sign() > 0 && !evm.Context().CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInsufficientFunds,
|
||||
"failed to transfer %s from address %s using the EVM block context transfer function",
|
||||
@@ -397,65 +417,82 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
|
||||
|
||||
// For eth type cosmos tx, some fields should be veified as zero values,
|
||||
// since we will only verify the signature against the hash of the MsgEthereumTx.Data
|
||||
if wrapperTx, ok := tx.(protoTxProvider); ok {
|
||||
protoTx := wrapperTx.GetProtoTx()
|
||||
body := protoTx.Body
|
||||
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
|
||||
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
|
||||
wrapperTx, ok := tx.(protoTxProvider)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid tx type %T, didn't implement interface protoTxProvider", tx)
|
||||
}
|
||||
|
||||
protoTx := wrapperTx.GetProtoTx()
|
||||
body := protoTx.Body
|
||||
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
|
||||
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
|
||||
}
|
||||
|
||||
if len(body.ExtensionOptions) != 1 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
|
||||
}
|
||||
|
||||
txFee := sdk.Coins{}
|
||||
txGasLimit := uint64(0)
|
||||
|
||||
params := vbd.evmKeeper.GetParams(ctx)
|
||||
chainID := vbd.evmKeeper.ChainID()
|
||||
ethCfg := params.ChainConfig.EthereumConfig(chainID)
|
||||
baseFee := vbd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
|
||||
for _, msg := range protoTx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
if len(body.ExtensionOptions) != 1 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
|
||||
// Validate `From` field
|
||||
if msgEthTx.From != "" {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid From %s, expect empty string", msgEthTx.From)
|
||||
}
|
||||
|
||||
txFee := sdk.Coins{}
|
||||
txGasLimit := uint64(0)
|
||||
txGasLimit += msgEthTx.GetGas()
|
||||
|
||||
for _, msg := range protoTx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
txGasLimit += msgEthTx.GetGas()
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data")
|
||||
}
|
||||
|
||||
params := vbd.evmKeeper.GetParams(ctx)
|
||||
chainID := vbd.evmKeeper.ChainID()
|
||||
ethCfg := params.ChainConfig.EthereumConfig(chainID)
|
||||
baseFee := vbd.evmKeeper.BaseFee(ctx, ethCfg)
|
||||
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
|
||||
return ctx, sdkerrors.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
|
||||
}
|
||||
|
||||
txFee = txFee.Add(sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(txData.Fee())))
|
||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data")
|
||||
}
|
||||
|
||||
authInfo := protoTx.AuthInfo
|
||||
if len(authInfo.SignerInfos) > 0 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
|
||||
// return error if contract creation or call are disabled through governance
|
||||
if !params.EnableCreate && txData.GetTo() == nil {
|
||||
return ctx, sdkerrors.Wrap(evmtypes.ErrCreateDisabled, "failed to create new contract")
|
||||
} else if !params.EnableCall && txData.GetTo() != nil {
|
||||
return ctx, sdkerrors.Wrap(evmtypes.ErrCallDisabled, "failed to call contract")
|
||||
}
|
||||
|
||||
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
|
||||
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
|
||||
return ctx, sdkerrors.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
|
||||
}
|
||||
|
||||
if !authInfo.Fee.Amount.IsEqual(txFee) {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee Amount (%s != %s)", authInfo.Fee.Amount, txFee)
|
||||
}
|
||||
txFee = txFee.Add(sdk.NewCoin(params.EvmDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
|
||||
}
|
||||
|
||||
if authInfo.Fee.GasLimit != txGasLimit {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee GasLimit (%d != %d)", authInfo.Fee.GasLimit, txGasLimit)
|
||||
}
|
||||
authInfo := protoTx.AuthInfo
|
||||
if len(authInfo.SignerInfos) > 0 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
|
||||
}
|
||||
|
||||
sigs := protoTx.Signatures
|
||||
if len(sigs) > 0 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty")
|
||||
}
|
||||
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
|
||||
}
|
||||
|
||||
if !authInfo.Fee.Amount.IsEqual(txFee) {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee Amount (%s != %s)", authInfo.Fee.Amount, txFee)
|
||||
}
|
||||
|
||||
if authInfo.Fee.GasLimit != txGasLimit {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee GasLimit (%d != %d)", authInfo.Fee.GasLimit, txGasLimit)
|
||||
}
|
||||
|
||||
sigs := protoTx.Signatures
|
||||
if len(sigs) > 0 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty")
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
@@ -511,7 +548,7 @@ func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat
|
||||
if ctx.IsCheckTx() && !simulate {
|
||||
params := mfd.evmKeeper.GetParams(ctx)
|
||||
ethCfg := params.ChainConfig.EthereumConfig(mfd.evmKeeper.ChainID())
|
||||
baseFee := mfd.evmKeeper.BaseFee(ctx, ethCfg)
|
||||
baseFee := mfd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
if baseFee == nil {
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
@@ -532,3 +569,36 @@ func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthEmitEventDecorator emit events in ante handler in case of tx execution failed (out of block gas limit).
|
||||
type EthEmitEventDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewEthEmitEventDecorator creates a new EthEmitEventDecorator
|
||||
func NewEthEmitEventDecorator(evmKeeper EVMKeeper) EthEmitEventDecorator {
|
||||
return EthEmitEventDecorator{evmKeeper}
|
||||
}
|
||||
|
||||
// AnteHandle emits some basic events for the eth messages
|
||||
func (eeed EthEmitEventDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// After eth tx passed ante handler, the fee is deducted and nonce increased, it shouldn't be ignored by json-rpc,
|
||||
// we need to emit some basic events at the very end of ante handler to be indexed by tendermint.
|
||||
txIndex := eeed.evmKeeper.GetTxIndexTransient(ctx)
|
||||
for i, msg := range tx.GetMsgs() {
|
||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
// emit ethereum tx hash as event, should be indexed by tm tx indexer for query purpose.
|
||||
// it's emitted in ante handler so we can query failed transaction (out of block gas limit).
|
||||
ctx.EventManager().EmitEvent(sdk.NewEvent(
|
||||
evmtypes.EventTypeEthereumTx,
|
||||
sdk.NewAttribute(evmtypes.AttributeKeyEthereumTxHash, msgEthTx.Hash),
|
||||
sdk.NewAttribute(evmtypes.AttributeKeyTxIndex, strconv.FormatUint(txIndex+uint64(i), 10)),
|
||||
))
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
+83
-40
@@ -1,6 +1,7 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@@ -14,12 +15,7 @@ import (
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
func nextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
|
||||
dec := ante.NewEthSigVerificationDecorator(suite.app.EvmKeeper)
|
||||
addr, privKey := tests.NewAddrKey()
|
||||
|
||||
signedTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
@@ -27,26 +23,40 @@ func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
|
||||
err := signedTx.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
unprotectedTx := evmtypes.NewTxContract(nil, 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||
unprotectedTx.From = addr.Hex()
|
||||
err = unprotectedTx.Sign(ethtypes.HomesteadSigner{}, tests.NewSigner(privKey))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
reCheckTx bool
|
||||
expPass bool
|
||||
name string
|
||||
tx sdk.Tx
|
||||
allowUnprotectedTxs bool
|
||||
reCheckTx bool
|
||||
expPass bool
|
||||
}{
|
||||
{"ReCheckTx", &invalidTx{}, true, false},
|
||||
{"invalid transaction type", &invalidTx{}, false, false},
|
||||
{"ReCheckTx", &invalidTx{}, false, true, false},
|
||||
{"invalid transaction type", &invalidTx{}, false, false, false},
|
||||
{
|
||||
"invalid sender",
|
||||
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &addr, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{"successful signature verification", signedTx, false, true},
|
||||
{"successful signature verification", signedTx, false, false, true},
|
||||
{"invalid, reject unprotected txs", unprotectedTx, false, false, false},
|
||||
{"successful, allow unprotected txs", unprotectedTx, true, false, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
|
||||
suite.evmParamsOption = func(params *evmtypes.Params) {
|
||||
params.AllowUnprotectedTxs = tc.allowUnprotectedTxs
|
||||
}
|
||||
suite.SetupTest()
|
||||
dec := ante.NewEthSigVerificationDecorator(suite.app.EvmKeeper)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@@ -55,11 +65,12 @@ func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
|
||||
}
|
||||
})
|
||||
}
|
||||
suite.evmParamsOption = nil
|
||||
}
|
||||
|
||||
func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
dec := ante.NewEthAccountVerificationDecorator(
|
||||
suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.EvmKeeper,
|
||||
suite.app.AccountKeeper, suite.app.EvmKeeper,
|
||||
)
|
||||
|
||||
addr := tests.GenerateAddress()
|
||||
@@ -134,7 +145,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||
tc.malleate()
|
||||
suite.Require().NoError(vmdb.Commit())
|
||||
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, nextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@@ -190,7 +201,7 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@@ -210,41 +221,61 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
||||
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), txGasLimit, big.NewInt(1), nil, nil, nil, nil)
|
||||
tx.From = addr.Hex()
|
||||
|
||||
ethCfg := suite.app.EvmKeeper.GetParams(suite.ctx).
|
||||
ChainConfig.EthereumConfig(suite.app.EvmKeeper.ChainID())
|
||||
baseFee := suite.app.EvmKeeper.GetBaseFee(suite.ctx, ethCfg)
|
||||
suite.Require().Equal(int64(1000000000), baseFee.Int64())
|
||||
|
||||
gasPrice := new(big.Int).Add(baseFee, evmtypes.DefaultPriorityReduction.BigInt())
|
||||
|
||||
tx2GasLimit := uint64(1000000)
|
||||
tx2 := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit, big.NewInt(1), 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}})
|
||||
tx2.From = addr.Hex()
|
||||
tx2Priority := int64(1)
|
||||
|
||||
dynamicFeeTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), tx2GasLimit,
|
||||
nil, // gasPrice
|
||||
new(big.Int).Add(baseFee, big.NewInt(evmtypes.DefaultPriorityReduction.Int64()*2)), // gasFeeCap
|
||||
evmtypes.DefaultPriorityReduction.BigInt(), // gasTipCap
|
||||
nil, ðtypes.AccessList{{Address: addr, StorageKeys: nil}})
|
||||
dynamicFeeTx.From = addr.Hex()
|
||||
dynamicFeeTxPriority := int64(1)
|
||||
|
||||
var vmdb *statedb.StateDB
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
tx sdk.Tx
|
||||
gasLimit uint64
|
||||
malleate func()
|
||||
expPass bool
|
||||
expPanic bool
|
||||
name string
|
||||
tx sdk.Tx
|
||||
gasLimit uint64
|
||||
malleate func()
|
||||
expPass bool
|
||||
expPanic bool
|
||||
expPriority int64
|
||||
}{
|
||||
{"invalid transaction type", &invalidTx{}, 0, func() {}, false, false},
|
||||
{"invalid transaction type", &invalidTx{}, math.MaxUint64, func() {}, false, false, 0},
|
||||
{
|
||||
"sender not found",
|
||||
evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||
0,
|
||||
math.MaxUint64,
|
||||
func() {},
|
||||
false, false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"gas limit too low",
|
||||
tx,
|
||||
0,
|
||||
math.MaxUint64,
|
||||
func() {},
|
||||
false, false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"not enough balance for fees",
|
||||
tx2,
|
||||
0,
|
||||
math.MaxUint64,
|
||||
func() {},
|
||||
false, false,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"not enough tx gas",
|
||||
@@ -254,6 +285,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||
},
|
||||
false, true,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"not enough block gas",
|
||||
@@ -261,21 +293,32 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
||||
0,
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||
|
||||
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(1))
|
||||
},
|
||||
false, true,
|
||||
0,
|
||||
},
|
||||
{
|
||||
"success",
|
||||
"success - legacy tx",
|
||||
tx2,
|
||||
config.DefaultMaxTxGasWanted, // it's capped
|
||||
tx2GasLimit, // it's capped
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||
|
||||
vmdb.AddBalance(addr, big.NewInt(1001000000000000))
|
||||
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(10000000000000000000))
|
||||
},
|
||||
true, false,
|
||||
tx2Priority,
|
||||
},
|
||||
{
|
||||
"success - dynamic fee tx",
|
||||
dynamicFeeTx,
|
||||
tx2GasLimit, // it's capped
|
||||
func() {
|
||||
vmdb.AddBalance(addr, big.NewInt(1001000000000000))
|
||||
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(10000000000000000000))
|
||||
},
|
||||
true, false,
|
||||
dynamicFeeTxPriority,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -287,19 +330,19 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
|
||||
|
||||
if tc.expPanic {
|
||||
suite.Require().Panics(func() {
|
||||
_, _ = dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1)), tc.tx, false, nextFn)
|
||||
_, _ = dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1)), tc.tx, false, NextFn)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter()), tc.tx, false, nextFn)
|
||||
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter()), tc.tx, false, NextFn)
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expPriority, ctx.Priority())
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
// TODO: needs to check the gasmeter limit issue
|
||||
// suite.Require().Equal(tc.gasLimit, ctx.GasMeter().Limit())
|
||||
suite.Require().Equal(tc.gasLimit, ctx.GasMeter().Limit())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -377,7 +420,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
|
||||
tc.malleate()
|
||||
suite.Require().NoError(vmdb.Commit())
|
||||
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@@ -456,12 +499,12 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
|
||||
|
||||
if tc.expPanic {
|
||||
suite.Require().Panics(func() {
|
||||
_, _ = dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
|
||||
_, _ = dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
@@ -498,7 +541,7 @@ func (suite AnteTestSuite) TestEthSetupContextDecorator() {
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
)
|
||||
|
||||
// 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, int64(gas))
|
||||
return feeCoins, priority, nil
|
||||
}
|
||||
|
||||
// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price
|
||||
// provided in a transaction.
|
||||
func getTxPriority(fees sdk.Coins, gas int64) int64 {
|
||||
var priority int64
|
||||
|
||||
for _, fee := range fees {
|
||||
gasPrice := fee.Amount.QuoRaw(gas)
|
||||
amt := gasPrice.Quo(types.DefaultPriorityReduction)
|
||||
p := int64(math.MaxInt64)
|
||||
|
||||
if amt.IsInt64() {
|
||||
p = amt.Int64()
|
||||
}
|
||||
|
||||
if priority == 0 || p < priority {
|
||||
priority = p
|
||||
}
|
||||
}
|
||||
|
||||
return priority
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
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/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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// GasWantedDecorator keeps track of the gasWanted amount on the current block in transient store
|
||||
// for BaseFee calculation.
|
||||
// NOTE: This decorator does not perform any validation
|
||||
type GasWantedDecorator struct {
|
||||
evmKeeper EVMKeeper
|
||||
feeMarketKeeper FeeMarketKeeper
|
||||
}
|
||||
|
||||
// NewGasWantedDecorator creates a new NewGasWantedDecorator
|
||||
func NewGasWantedDecorator(
|
||||
evmKeeper EVMKeeper,
|
||||
feeMarketKeeper FeeMarketKeeper,
|
||||
) GasWantedDecorator {
|
||||
return GasWantedDecorator{
|
||||
evmKeeper,
|
||||
feeMarketKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
params := gwd.evmKeeper.GetParams(ctx)
|
||||
ethCfg := params.ChainConfig.EthereumConfig(gwd.evmKeeper.ChainID())
|
||||
|
||||
blockHeight := big.NewInt(ctx.BlockHeight())
|
||||
isLondon := ethCfg.IsLondon(blockHeight)
|
||||
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok || !isLondon {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
gasWanted := feeTx.GetGas()
|
||||
feeMktParams := gwd.feeMarketKeeper.GetParams(ctx)
|
||||
|
||||
// Add total gasWanted to cumulative in block transientStore in FeeMarket module
|
||||
if feeMktParams.IsBaseFeeEnabled(ctx.BlockHeight()) {
|
||||
if _, err := gwd.feeMarketKeeper.AddTransientGasWanted(ctx, gasWanted); err != nil {
|
||||
return ctx, sdkerrors.Wrapf(err, "failed to add gas wanted to transient store")
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
func (suite AnteTestSuite) TestGasWantedDecorator() {
|
||||
suite.enableFeemarket = true
|
||||
suite.SetupTest()
|
||||
dec := ante.NewGasWantedDecorator(suite.app.EvmKeeper, suite.app.FeeMarketKeeper)
|
||||
from, fromPrivKey := tests.NewAddrKey()
|
||||
to := tests.GenerateAddress()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
expectedGasWanted uint64
|
||||
malleate func() sdk.Tx
|
||||
}{
|
||||
{
|
||||
"Cosmos Tx",
|
||||
TestGasLimit,
|
||||
func() sdk.Tx {
|
||||
denom := evmtypes.DefaultEVMDenom
|
||||
testMsg := banktypes.MsgSend{
|
||||
FromAddress: "evmos1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ptzkucp",
|
||||
ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn",
|
||||
Amount: sdk.Coins{sdk.Coin{Amount: sdkmath.NewInt(10), Denom: denom}},
|
||||
}
|
||||
txBuilder := suite.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), "stake", &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
},
|
||||
{
|
||||
"Ethereum Legacy Tx",
|
||||
TestGasLimit,
|
||||
func() sdk.Tx {
|
||||
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, nil)
|
||||
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
"Ethereum Access List Tx",
|
||||
TestGasLimit,
|
||||
func() sdk.Tx {
|
||||
emptyAccessList := ethtypes.AccessList{}
|
||||
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, &emptyAccessList)
|
||||
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
"Ethereum Dynamic Fee Tx (EIP1559)",
|
||||
TestGasLimit,
|
||||
func() sdk.Tx {
|
||||
emptyAccessList := ethtypes.AccessList{}
|
||||
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), big.NewInt(100), big.NewInt(50), &emptyAccessList)
|
||||
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
"EIP712 message",
|
||||
200000,
|
||||
func() sdk.Tx {
|
||||
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
||||
gas := uint64(200000)
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, from.Bytes())
|
||||
suite.Require().NoError(acc.SetSequence(1))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
tx := suite.CreateTestEIP712TxBuilderMsgSend(acc.GetAddress(), fromPrivKey, suite.ctx.ChainID(), gas, amount)
|
||||
return tx.GetTx()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// cumulative gas wanted from all test transactions in the same block
|
||||
var expectedGasWanted uint64
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
_, err := dec.AnteHandle(suite.ctx, tc.malleate(), false, NextFn)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
gasWanted := suite.app.FeeMarketKeeper.GetTransientGasWanted(suite.ctx)
|
||||
expectedGasWanted += tc.expectedGasWanted
|
||||
suite.Require().Equal(expectedGasWanted, gasWanted)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// MinGasPriceDecorator will check if the transaction's fee is at least as large
|
||||
// as the MinGasPrices param. If fee is too low, decorator returns error and tx
|
||||
// is rejected. This applies for both CheckTx and DeliverTx
|
||||
// If fee is high enough, then call next AnteHandler
|
||||
// CONTRACT: Tx must implement FeeTx to use MinGasPriceDecorator
|
||||
type MinGasPriceDecorator struct {
|
||||
feesKeeper FeeMarketKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
func NewMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) MinGasPriceDecorator {
|
||||
return MinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
|
||||
}
|
||||
|
||||
func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
|
||||
}
|
||||
|
||||
minGasPrice := mpd.feesKeeper.GetParams(ctx).MinGasPrice
|
||||
|
||||
// Short-circuit if min gas price is 0 or if simulating
|
||||
if minGasPrice.IsZero() || simulate {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
evmParams := mpd.evmKeeper.GetParams(ctx)
|
||||
minGasPrices := sdk.DecCoins{
|
||||
{
|
||||
Denom: evmParams.EvmDenom,
|
||||
Amount: minGasPrice,
|
||||
},
|
||||
}
|
||||
|
||||
feeCoins := feeTx.GetFee()
|
||||
gas := feeTx.GetGas()
|
||||
|
||||
requiredFees := make(sdk.Coins, 0)
|
||||
|
||||
// Determine the required fees by multiplying each required minimum gas
|
||||
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
|
||||
gasLimit := sdk.NewDecFromBigInt(new(big.Int).SetUint64(gas))
|
||||
|
||||
for _, gp := range minGasPrices {
|
||||
fee := gp.Amount.Mul(gasLimit).Ceil().RoundInt()
|
||||
if fee.IsPositive() {
|
||||
requiredFees = requiredFees.Add(sdk.Coin{Denom: gp.Denom, Amount: fee})
|
||||
}
|
||||
}
|
||||
|
||||
if !feeCoins.IsAnyGTE(requiredFees) {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee,
|
||||
"provided fee < minimum global fee (%s < %s). Please increase the gas price.",
|
||||
feeCoins,
|
||||
requiredFees)
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthMinGasPriceDecorator will check if the transaction's fee is at least as large
|
||||
// as the MinGasPrices param. If fee is too low, decorator returns error and tx
|
||||
// is rejected. This applies to both CheckTx and DeliverTx and regardless
|
||||
// if London hard fork or fee market params (EIP-1559) are enabled.
|
||||
// If fee is high enough, then call next AnteHandler
|
||||
type EthMinGasPriceDecorator struct {
|
||||
feesKeeper FeeMarketKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
func NewEthMinGasPriceDecorator(fk FeeMarketKeeper, ek EVMKeeper) EthMinGasPriceDecorator {
|
||||
return EthMinGasPriceDecorator{feesKeeper: fk, evmKeeper: ek}
|
||||
}
|
||||
|
||||
func (empd EthMinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
minGasPrice := empd.feesKeeper.GetParams(ctx).MinGasPrice
|
||||
|
||||
// short-circuit if min gas price is 0
|
||||
if minGasPrice.IsZero() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
paramsEvm := empd.evmKeeper.GetParams(ctx)
|
||||
ethCfg := paramsEvm.ChainConfig.EthereumConfig(empd.evmKeeper.ChainID())
|
||||
baseFee := empd.evmKeeper.GetBaseFee(ctx, ethCfg)
|
||||
|
||||
for _, msg := range tx.GetMsgs() {
|
||||
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrUnknownRequest,
|
||||
"invalid message type %T, expected %T",
|
||||
msg, (*evmtypes.MsgEthereumTx)(nil),
|
||||
)
|
||||
}
|
||||
|
||||
feeAmt := ethMsg.GetFee()
|
||||
|
||||
// For dynamic transactions, GetFee() uses the GasFeeCap value, which
|
||||
// is the maximum gas price that the signer can pay. In practice, the
|
||||
// signer can pay less, if the block's BaseFee is lower. So, in this case,
|
||||
// we use the EffectiveFee. If the feemarket formula results in a BaseFee
|
||||
// that lowers EffectivePrice until it is < MinGasPrices, the users must
|
||||
// increase the GasTipCap (priority fee) until EffectivePrice > MinGasPrices.
|
||||
// Transactions with MinGasPrices * gasUsed < tx fees < EffectiveFee are rejected
|
||||
// by the feemarket AnteHandle
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(ethMsg.Data)
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrapf(err, "failed to unpack tx data %s", ethMsg.Hash)
|
||||
}
|
||||
|
||||
if txData.TxType() != ethtypes.LegacyTxType {
|
||||
feeAmt = ethMsg.GetEffectiveFee(baseFee)
|
||||
}
|
||||
|
||||
gasLimit := sdk.NewDecFromBigInt(new(big.Int).SetUint64(ethMsg.GetGas()))
|
||||
|
||||
requiredFee := minGasPrice.Mul(gasLimit)
|
||||
fee := sdk.NewDecFromBigInt(feeAmt)
|
||||
|
||||
if fee.LT(requiredFee) {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInsufficientFee,
|
||||
"provided fee < minimum global fee (%d < %d). Please increase the priority tip (for EIP-1559 txs) or the gas prices (for access list or legacy txs)", //nolint:lll
|
||||
fee.TruncateInt().Int64(), requiredFee.TruncateInt().Int64(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
var execTypes = []struct {
|
||||
name string
|
||||
isCheckTx bool
|
||||
simulate bool
|
||||
}{
|
||||
{"deliverTx", false, false},
|
||||
{"deliverTxSimulate", false, true},
|
||||
}
|
||||
|
||||
func (s AnteTestSuite) TestMinGasPriceDecorator() {
|
||||
denom := evmtypes.DefaultEVMDenom
|
||||
testMsg := banktypes.MsgSend{
|
||||
FromAddress: "evmos1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ptzkucp",
|
||||
ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn",
|
||||
Amount: sdk.Coins{sdk.Coin{Amount: sdkmath.NewInt(10), Denom: denom}},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func() sdk.Tx
|
||||
expPass bool
|
||||
errMsg string
|
||||
allowPassOnSimulate bool
|
||||
}{
|
||||
{
|
||||
"invalid cosmos tx type",
|
||||
func() sdk.Tx {
|
||||
return &invalidTx{}
|
||||
},
|
||||
false,
|
||||
"must be a FeeTx",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid cosmos tx with MinGasPrices = 0, gasPrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(0), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
true,
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid cosmos tx with MinGasPrices = 0, gasPrice > 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
true,
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid cosmos tx with MinGasPrices = 10, gasPrice = 10",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
true,
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid cosmos tx with MinGasPrices = 10, gasPrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(0), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid cosmos tx with wrong denom",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(10), "stake", &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, et := range execTypes {
|
||||
for _, tc := range testCases {
|
||||
s.Run(et.name+"_"+tc.name, func() {
|
||||
// s.SetupTest(et.isCheckTx)
|
||||
ctx := s.ctx.WithIsReCheckTx(et.isCheckTx)
|
||||
dec := ante.NewMinGasPriceDecorator(s.app.FeeMarketKeeper, s.app.EvmKeeper)
|
||||
_, err := dec.AnteHandle(ctx, tc.malleate(), et.simulate, NextFn)
|
||||
|
||||
if tc.expPass || (et.simulate && tc.allowPassOnSimulate) {
|
||||
s.Require().NoError(err, tc.name)
|
||||
} else {
|
||||
s.Require().Error(err, tc.name)
|
||||
s.Require().Contains(err.Error(), tc.errMsg, tc.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s AnteTestSuite) TestEthMinGasPriceDecorator() {
|
||||
denom := evmtypes.DefaultEVMDenom
|
||||
from, privKey := tests.NewAddrKey()
|
||||
to := tests.GenerateAddress()
|
||||
emptyAccessList := ethtypes.AccessList{}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
malleate func() sdk.Tx
|
||||
expPass bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
"invalid tx type",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
return &invalidTx{}
|
||||
},
|
||||
false,
|
||||
"invalid message type",
|
||||
},
|
||||
{
|
||||
"wrong tx type",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
testMsg := banktypes.MsgSend{
|
||||
FromAddress: "evmos1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ptzkucp",
|
||||
ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn",
|
||||
Amount: sdk.Coins{sdk.Coin{Amount: sdkmath.NewInt(10), Denom: denom}},
|
||||
}
|
||||
txBuilder := s.CreateTestCosmosTxBuilder(sdkmath.NewInt(0), denom, &testMsg)
|
||||
return txBuilder.GetTx()
|
||||
},
|
||||
false,
|
||||
"invalid message type",
|
||||
},
|
||||
{
|
||||
"valid: invalid tx type with MinGasPrices = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
return &invalidTx{}
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid legacy tx with MinGasPrices = 0, gasPrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, nil)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid legacy tx with MinGasPrices = 0, gasPrice > 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(10), nil, nil, nil)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid legacy tx with MinGasPrices = 10, gasPrice = 10",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(10), nil, nil, nil)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"invalid legacy tx with MinGasPrices = 10, gasPrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, nil)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
},
|
||||
{
|
||||
"valid dynamic tx with MinGasPrices = 0, EffectivePrice = 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(0), big.NewInt(0), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid dynamic tx with MinGasPrices = 0, EffectivePrice > 0",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.ZeroDec()
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(100), big.NewInt(50), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"valid dynamic tx with MinGasPrices < EffectivePrice",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(100), big.NewInt(100), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
{
|
||||
"invalid dynamic tx with MinGasPrices > EffectivePrice",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(0), big.NewInt(0), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
},
|
||||
{
|
||||
"invalid dynamic tx with MinGasPrices > BaseFee, MinGasPrices > EffectivePrice",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(100)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
feemarketParams := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
feemarketParams.BaseFee = sdkmath.NewInt(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, feemarketParams)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(1000), big.NewInt(0), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
false,
|
||||
"provided fee < minimum global fee",
|
||||
},
|
||||
{
|
||||
"valid dynamic tx with MinGasPrices > BaseFee, MinGasPrices < EffectivePrice (big GasTipCap)",
|
||||
func() sdk.Tx {
|
||||
params := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
params.MinGasPrice = sdk.NewDec(100)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, params)
|
||||
|
||||
feemarketParams := s.app.FeeMarketKeeper.GetParams(s.ctx)
|
||||
feemarketParams.BaseFee = sdkmath.NewInt(10)
|
||||
s.app.FeeMarketKeeper.SetParams(s.ctx, feemarketParams)
|
||||
|
||||
msg := s.BuildTestEthTx(from, to, nil, make([]byte, 0), nil, big.NewInt(1000), big.NewInt(101), &emptyAccessList)
|
||||
return s.CreateTestTx(msg, privKey, 1, false)
|
||||
},
|
||||
true,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, et := range execTypes {
|
||||
for _, tc := range testCases {
|
||||
s.Run(et.name+"_"+tc.name, func() {
|
||||
// s.SetupTest(et.isCheckTx)
|
||||
s.SetupTest()
|
||||
dec := ante.NewEthMinGasPriceDecorator(s.app.FeeMarketKeeper, s.app.EvmKeeper)
|
||||
_, err := dec.AnteHandle(s.ctx, tc.malleate(), et.simulate, NextFn)
|
||||
|
||||
if tc.expPass {
|
||||
s.Require().NoError(err, tc.name)
|
||||
} else {
|
||||
s.Require().Error(err, tc.name)
|
||||
s.Require().Contains(err.Error(), tc.errMsg, tc.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
-15
@@ -17,19 +17,20 @@ import (
|
||||
// HandlerOptions extend the SDK's AnteHandler options by requiring the IBC
|
||||
// channel keeper, EVM Keeper and Fee Market Keeper.
|
||||
type HandlerOptions struct {
|
||||
AccountKeeper evmtypes.AccountKeeper
|
||||
BankKeeper evmtypes.BankKeeper
|
||||
IBCKeeper *ibckeeper.Keeper
|
||||
FeeMarketKeeper evmtypes.FeeMarketKeeper
|
||||
EvmKeeper EVMKeeper
|
||||
FeegrantKeeper ante.FeegrantKeeper
|
||||
SignModeHandler authsigning.SignModeHandler
|
||||
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error
|
||||
MaxTxGasWanted uint64
|
||||
TxFeeChecker ante.TxFeeChecker
|
||||
AccountKeeper evmtypes.AccountKeeper
|
||||
BankKeeper evmtypes.BankKeeper
|
||||
IBCKeeper *ibckeeper.Keeper
|
||||
FeeMarketKeeper evmtypes.FeeMarketKeeper
|
||||
EvmKeeper EVMKeeper
|
||||
FeegrantKeeper ante.FeegrantKeeper
|
||||
SignModeHandler authsigning.SignModeHandler
|
||||
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error
|
||||
MaxTxGasWanted uint64
|
||||
ExtensionOptionChecker ante.ExtensionOptionChecker
|
||||
TxFeeChecker ante.TxFeeChecker
|
||||
}
|
||||
|
||||
func (options HandlerOptions) Validate() error {
|
||||
func (options HandlerOptions) validate() error {
|
||||
if options.AccountKeeper == nil {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler")
|
||||
}
|
||||
@@ -50,14 +51,17 @@ func (options HandlerOptions) Validate() error {
|
||||
|
||||
func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
return sdk.ChainAnteDecorators(
|
||||
NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first
|
||||
NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices
|
||||
NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first
|
||||
NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices
|
||||
NewEthMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), // Check eth effective gas price against the global MinGasPrice
|
||||
NewEthValidateBasicDecorator(options.EvmKeeper),
|
||||
NewEthSigVerificationDecorator(options.EvmKeeper),
|
||||
NewEthAccountVerificationDecorator(options.AccountKeeper, options.BankKeeper, options.EvmKeeper),
|
||||
NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted),
|
||||
NewEthAccountVerificationDecorator(options.AccountKeeper, options.EvmKeeper),
|
||||
NewCanTransferDecorator(options.EvmKeeper),
|
||||
NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted),
|
||||
NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator.
|
||||
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
|
||||
NewEthEmitEventDecorator(options.EvmKeeper), // emit eth tx hash and index at the very last ante handler.
|
||||
)
|
||||
}
|
||||
|
||||
@@ -65,6 +69,8 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
return sdk.ChainAnteDecorators(
|
||||
RejectMessagesDecorator{}, // reject MsgEthereumTxs
|
||||
ante.NewSetUpContextDecorator(),
|
||||
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
|
||||
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
|
||||
ante.NewValidateBasicDecorator(),
|
||||
ante.NewTxTimeoutHeightDecorator(),
|
||||
ante.NewValidateMemoDecorator(options.AccountKeeper),
|
||||
@@ -77,6 +83,7 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
|
||||
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
|
||||
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
|
||||
ibcante.NewRedundantRelayDecorator(options.IBCKeeper),
|
||||
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,6 +93,7 @@ func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
|
||||
ante.NewSetUpContextDecorator(),
|
||||
// NOTE: extensions option decorator removed
|
||||
// ante.NewRejectExtensionOptionsDecorator(),
|
||||
NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
|
||||
ante.NewValidateBasicDecorator(),
|
||||
ante.NewTxTimeoutHeightDecorator(),
|
||||
ante.NewValidateMemoDecorator(options.AccountKeeper),
|
||||
@@ -99,5 +107,6 @@ func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
|
||||
NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
|
||||
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
|
||||
ibcante.NewRedundantRelayDecorator(options.IBCKeeper),
|
||||
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
|
||||
)
|
||||
}
|
||||
|
||||
+19
-5
@@ -5,6 +5,8 @@ import (
|
||||
|
||||
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
evm "github.com/cerc-io/laconicd/x/evm/vm"
|
||||
feemarkettypes "github.com/cerc-io/laconicd/x/feemarket/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
tx "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -13,21 +15,33 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// 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
|
||||
type EVMKeeper interface {
|
||||
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) evm.EVM
|
||||
DeductTxCostsFromUserBalance(
|
||||
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
|
||||
) (sdk.Coins, error)
|
||||
BaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int
|
||||
) (fees sdk.Coins, priority int64, err error)
|
||||
GetBalance(ctx sdk.Context, addr common.Address) *big.Int
|
||||
ResetTransientGasUsed(ctx sdk.Context)
|
||||
GetTxIndexTransient(ctx sdk.Context) uint64
|
||||
}
|
||||
|
||||
type protoTxProvider interface {
|
||||
GetProtoTx() *tx.Tx
|
||||
}
|
||||
|
||||
// FeeMarketKeeper defines the expected keeper interface used on the AnteHandler
|
||||
type FeeMarketKeeper interface {
|
||||
GetParams(ctx sdk.Context) (params feemarkettypes.Params)
|
||||
AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error)
|
||||
}
|
||||
|
||||
+186
-15
@@ -1,10 +1,16 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cerc-io/laconicd/ethereum/eip712"
|
||||
"github.com/cerc-io/laconicd/types"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
@@ -16,8 +22,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
cryptocodec "github.com/cerc-io/laconicd/crypto/codec"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
@@ -25,6 +30,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
"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"
|
||||
@@ -37,6 +43,10 @@ import (
|
||||
"github.com/cerc-io/laconicd/x/evm/statedb"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
feemarkettypes "github.com/cerc-io/laconicd/x/feemarket/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
evtypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/feegrant"
|
||||
types5 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
)
|
||||
@@ -51,8 +61,11 @@ type AnteTestSuite struct {
|
||||
ethSigner ethtypes.Signer
|
||||
enableFeemarket bool
|
||||
enableLondonHF bool
|
||||
evmParamsOption func(*evmtypes.Params)
|
||||
}
|
||||
|
||||
const TestGasLimit uint64 = 100000
|
||||
|
||||
func (suite *AnteTestSuite) StateDB() *statedb.StateDB {
|
||||
return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes())))
|
||||
}
|
||||
@@ -60,7 +73,7 @@ func (suite *AnteTestSuite) StateDB() *statedb.StateDB {
|
||||
func (suite *AnteTestSuite) SetupTest() {
|
||||
checkTx := false
|
||||
|
||||
suite.app = app.Setup(suite.T(), checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
|
||||
suite.app = app.Setup(checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
|
||||
if suite.enableFeemarket {
|
||||
// setup feemarketGenesis params
|
||||
feemarketGenesis := feemarkettypes.DefaultGenesisState()
|
||||
@@ -71,14 +84,19 @@ func (suite *AnteTestSuite) SetupTest() {
|
||||
suite.Require().NoError(err)
|
||||
genesis[feemarkettypes.ModuleName] = app.AppCodec().MustMarshalJSON(feemarketGenesis)
|
||||
}
|
||||
evmGenesis := evmtypes.DefaultGenesisState()
|
||||
evmGenesis.Params.AllowUnprotectedTxs = false
|
||||
if !suite.enableLondonHF {
|
||||
evmGenesis := evmtypes.DefaultGenesisState()
|
||||
maxInt := sdk.NewInt(math.MaxInt64)
|
||||
maxInt := sdkmath.NewInt(math.MaxInt64)
|
||||
evmGenesis.Params.ChainConfig.LondonBlock = &maxInt
|
||||
evmGenesis.Params.ChainConfig.ArrowGlacierBlock = &maxInt
|
||||
evmGenesis.Params.ChainConfig.MergeForkBlock = &maxInt
|
||||
genesis[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis)
|
||||
evmGenesis.Params.ChainConfig.GrayGlacierBlock = &maxInt
|
||||
evmGenesis.Params.ChainConfig.MergeNetsplitBlock = &maxInt
|
||||
}
|
||||
if suite.evmParamsOption != nil {
|
||||
suite.evmParamsOption(&evmGenesis.Params)
|
||||
}
|
||||
genesis[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis)
|
||||
return genesis
|
||||
})
|
||||
|
||||
@@ -96,7 +114,7 @@ func (suite *AnteTestSuite) SetupTest() {
|
||||
|
||||
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
|
||||
|
||||
options := ante.HandlerOptions{
|
||||
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
|
||||
AccountKeeper: suite.app.AccountKeeper,
|
||||
BankKeeper: suite.app.BankKeeper,
|
||||
EvmKeeper: suite.app.EvmKeeper,
|
||||
@@ -105,11 +123,10 @@ func (suite *AnteTestSuite) SetupTest() {
|
||||
FeeMarketKeeper: suite.app.FeeMarketKeeper,
|
||||
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
}
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NoError(options.Validate())
|
||||
|
||||
suite.anteHandler = ante.NewAnteHandler(options)
|
||||
suite.anteHandler = anteHandler
|
||||
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
|
||||
}
|
||||
|
||||
@@ -119,6 +136,38 @@ func TestAnteTestSuite(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func (s *AnteTestSuite) BuildTestEthTx(
|
||||
from common.Address,
|
||||
to common.Address,
|
||||
amount *big.Int,
|
||||
input []byte,
|
||||
gasPrice *big.Int,
|
||||
gasFeeCap *big.Int,
|
||||
gasTipCap *big.Int,
|
||||
accesses *ethtypes.AccessList,
|
||||
) *evmtypes.MsgEthereumTx {
|
||||
chainID := s.app.EvmKeeper.ChainID()
|
||||
nonce := s.app.EvmKeeper.GetNonce(
|
||||
s.ctx,
|
||||
common.BytesToAddress(from.Bytes()),
|
||||
)
|
||||
|
||||
msgEthereumTx := evmtypes.NewTx(
|
||||
chainID,
|
||||
nonce,
|
||||
&to,
|
||||
amount,
|
||||
TestGasLimit,
|
||||
gasPrice,
|
||||
gasFeeCap,
|
||||
gasTipCap,
|
||||
input,
|
||||
accesses,
|
||||
)
|
||||
msgEthereumTx.From = from.String()
|
||||
return msgEthereumTx
|
||||
}
|
||||
|
||||
// CreateTestTx is a helper function to create a tx given multiple inputs.
|
||||
func (suite *AnteTestSuite) CreateTestTx(
|
||||
msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey, accNum uint64, signCosmosTx bool,
|
||||
@@ -150,13 +199,14 @@ func (suite *AnteTestSuite) CreateTestTxBuilder(
|
||||
err = msg.Sign(suite.ethSigner, tests.NewSigner(priv))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
msg.From = ""
|
||||
err = builder.SetMsgs(msg)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
txData, err := evmtypes.UnpackTxData(msg.Data)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
fees := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewIntFromBigInt(txData.Fee())))
|
||||
fees := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
|
||||
builder.SetFeeAmount(fees)
|
||||
builder.SetGasLimit(msg.GetGas())
|
||||
|
||||
@@ -199,10 +249,21 @@ func (suite *AnteTestSuite) CreateTestTxBuilder(
|
||||
return txBuilder
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestCosmosTxBuilder(gasPrice sdkmath.Int, denom string, msgs ...sdk.Msg) client.TxBuilder {
|
||||
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
txBuilder.SetGasLimit(TestGasLimit)
|
||||
fees := &sdk.Coins{{Denom: denom, Amount: gasPrice.MulRaw(int64(TestGasLimit))}}
|
||||
txBuilder.SetFeeAmount(*fees)
|
||||
err := txBuilder.SetMsgs(msgs...)
|
||||
suite.Require().NoError(err)
|
||||
return txBuilder
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
// Build MsgSend
|
||||
recipient := sdk.AccAddress(common.Address{}.Bytes())
|
||||
msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(1))))
|
||||
msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(1))))
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
|
||||
}
|
||||
|
||||
@@ -210,10 +271,111 @@ func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAdd
|
||||
// Build MsgSend
|
||||
valEthAddr := tests.GenerateAddress()
|
||||
valAddr := sdk.ValAddress(valEthAddr.Bytes())
|
||||
msgSend := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
|
||||
msgSend := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdkmath.NewInt(20)))
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgCreateValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
// Build MsgCreateValidator
|
||||
valAddr := sdk.ValAddress(from.Bytes())
|
||||
privEd := ed25519.GenPrivKey()
|
||||
msgCreate, err := types3.NewMsgCreateValidator(
|
||||
valAddr,
|
||||
privEd.PubKey(),
|
||||
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)),
|
||||
// TODO: can this values be empty strings?
|
||||
types3.NewDescription("moniker", "indentity", "website", "security_contract", "details"),
|
||||
types3.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.OneDec()),
|
||||
sdk.OneInt(),
|
||||
)
|
||||
suite.Require().NoError(err)
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgCreate)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712SubmitProposal(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, deposit sdk.Coins) client.TxBuilder {
|
||||
proposal, ok := types5.ContentFromProposalType("My proposal", "My description", types5.ProposalTypeText)
|
||||
suite.Require().True(ok)
|
||||
msgSubmit, err := types5.NewMsgSubmitProposal(proposal, deposit, from)
|
||||
suite.Require().NoError(err)
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSubmit)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712GrantAllowance(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
spendLimit := sdk.NewCoins(sdk.NewInt64Coin(evmtypes.DefaultEVMDenom, 10))
|
||||
threeHours := time.Now().Add(3 * time.Hour)
|
||||
basic := &feegrant.BasicAllowance{
|
||||
SpendLimit: spendLimit,
|
||||
Expiration: &threeHours,
|
||||
}
|
||||
granted := tests.GenerateAddress()
|
||||
grantedAddr := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, granted.Bytes())
|
||||
msgGrant, err := feegrant.NewMsgGrantAllowance(basic, from, grantedAddr.GetAddress())
|
||||
suite.Require().NoError(err)
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgGrant)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgEditValidator(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
valAddr := sdk.ValAddress(from.Bytes())
|
||||
msgEdit := types3.NewMsgEditValidator(
|
||||
valAddr,
|
||||
types3.NewDescription("moniker", "identity", "website", "security_contract", "details"),
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgEdit)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712MsgSubmitEvidence(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||
pk := ed25519.GenPrivKey()
|
||||
msgEvidence, err := evtypes.NewMsgSubmitEvidence(from, &evtypes.Equivocation{
|
||||
Height: 11,
|
||||
Time: time.Now().UTC(),
|
||||
Power: 100,
|
||||
ConsensusAddress: pk.PubKey().Address().String(),
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgEvidence)
|
||||
}
|
||||
|
||||
// StdSignBytes returns the bytes to sign for a transaction.
|
||||
func StdSignBytes(cdc *codec.LegacyAmino, chainID string, accnum uint64, sequence uint64, timeout uint64, fee legacytx.StdFee, msgs []sdk.Msg, memo string, tip *txtypes.Tip) []byte {
|
||||
msgsBytes := make([]json.RawMessage, 0, len(msgs))
|
||||
for _, msg := range msgs {
|
||||
legacyMsg, ok := msg.(legacytx.LegacyMsg)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("expected %T when using amino JSON", (*legacytx.LegacyMsg)(nil)))
|
||||
}
|
||||
|
||||
msgsBytes = append(msgsBytes, json.RawMessage(legacyMsg.GetSignBytes()))
|
||||
}
|
||||
|
||||
var stdTip *legacytx.StdTip
|
||||
if tip != nil {
|
||||
if tip.Tipper == "" {
|
||||
panic(fmt.Errorf("tipper cannot be empty"))
|
||||
}
|
||||
|
||||
stdTip = &legacytx.StdTip{Amount: tip.Amount, Tipper: tip.Tipper}
|
||||
}
|
||||
|
||||
bz, err := cdc.MarshalJSON(legacytx.StdSignDoc{
|
||||
AccountNumber: accnum,
|
||||
ChainID: chainID,
|
||||
Fee: json.RawMessage(fee.Bytes()),
|
||||
Memo: memo,
|
||||
Msgs: msgsBytes,
|
||||
Sequence: sequence,
|
||||
TimeoutHeight: timeout,
|
||||
Tip: stdTip,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
|
||||
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msg sdk.Msg,
|
||||
) client.TxBuilder {
|
||||
@@ -228,6 +390,11 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
|
||||
|
||||
// GenerateTypedData TypedData
|
||||
var ethermintCodec codec.ProtoCodecMarshaler
|
||||
registry := codectypes.NewInterfaceRegistry()
|
||||
types.RegisterInterfaces(registry)
|
||||
ethermintCodec = codec.NewProtoCodec(registry)
|
||||
cryptocodec.RegisterInterfaces(registry)
|
||||
|
||||
fee := legacytx.NewStdFee(gas, gasAmount)
|
||||
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
|
||||
|
||||
@@ -281,6 +448,10 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
|
||||
return builder
|
||||
}
|
||||
|
||||
func NextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
var _ sdk.Tx = &invalidTx{}
|
||||
|
||||
type invalidTx struct{}
|
||||
|
||||
+175
-128
@@ -11,8 +11,11 @@ import (
|
||||
"github.com/rakyll/statik/fs"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
|
||||
@@ -22,17 +25,14 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/server/config"
|
||||
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
|
||||
"github.com/cosmos/cosmos-sdk/store/streaming"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/v2alpha1"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/posthandler"
|
||||
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
@@ -66,6 +66,7 @@ import (
|
||||
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
|
||||
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
||||
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
|
||||
@@ -86,10 +87,6 @@ import (
|
||||
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
|
||||
"github.com/cosmos/ibc-go/v5/modules/apps/transfer"
|
||||
ibctransferkeeper "github.com/cosmos/ibc-go/v5/modules/apps/transfer/keeper"
|
||||
ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
|
||||
@@ -103,12 +100,13 @@ import (
|
||||
// unnamed import of statik for swagger UI support
|
||||
_ "github.com/cerc-io/laconicd/client/docs/statik"
|
||||
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
srvflags "github.com/cerc-io/laconicd/server/flags"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
"github.com/cerc-io/laconicd/x/evm"
|
||||
|
||||
// evmrest "github.com/cerc-io/laconicd/x/evm/client/rest"
|
||||
evmkeeper "github.com/cerc-io/laconicd/x/evm/keeper"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/cerc-io/laconicd/x/evm/vm/geth"
|
||||
"github.com/cerc-io/laconicd/x/feemarket"
|
||||
feemarketkeeper "github.com/cerc-io/laconicd/x/feemarket/keeper"
|
||||
feemarkettypes "github.com/cerc-io/laconicd/x/feemarket/types"
|
||||
@@ -134,10 +132,10 @@ func init() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
DefaultNodeHome = filepath.Join(userHomeDir, ".laconicd")
|
||||
DefaultNodeHome = filepath.Join(userHomeDir, ".ethermintd")
|
||||
}
|
||||
|
||||
const appName = "laconicd"
|
||||
const appName = "ethermintd"
|
||||
|
||||
var (
|
||||
// DefaultNodeHome default home directories for the application daemon
|
||||
@@ -154,10 +152,10 @@ var (
|
||||
staking.AppModuleBasic{},
|
||||
mint.AppModuleBasic{},
|
||||
distr.AppModuleBasic{},
|
||||
gov.NewAppModuleBasic(
|
||||
[]govclient.ProposalHandler{paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.LegacyProposalHandler, upgradeclient.LegacyCancelProposalHandler,
|
||||
ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler},
|
||||
),
|
||||
gov.NewAppModuleBasic([]govclient.ProposalHandler{
|
||||
paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.LegacyProposalHandler, upgradeclient.LegacyCancelProposalHandler,
|
||||
ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler,
|
||||
}),
|
||||
params.AppModuleBasic{},
|
||||
crisis.AppModuleBasic{},
|
||||
slashing.AppModuleBasic{},
|
||||
@@ -171,7 +169,7 @@ var (
|
||||
// Ethermint modules
|
||||
evm.AppModuleBasic{},
|
||||
feemarket.AppModuleBasic{},
|
||||
// Cerc-io laconic modules
|
||||
// Laconic modules
|
||||
auction.AppModuleBasic{},
|
||||
bond.AppModuleBasic{},
|
||||
nameservice.AppModuleBasic{},
|
||||
@@ -215,7 +213,8 @@ type EthermintApp struct {
|
||||
cdc *codec.LegacyAmino
|
||||
appCodec codec.Codec
|
||||
interfaceRegistry types.InterfaceRegistry
|
||||
invCheckPeriod uint
|
||||
|
||||
invCheckPeriod uint
|
||||
|
||||
// keys to access the substores
|
||||
keys map[string]*storetypes.KVStoreKey
|
||||
@@ -281,13 +280,25 @@ func NewEthermintApp(
|
||||
cdc := encodingConfig.Amino
|
||||
interfaceRegistry := encodingConfig.InterfaceRegistry
|
||||
|
||||
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||
bApp := baseapp.NewBaseApp(
|
||||
appName,
|
||||
logger,
|
||||
db,
|
||||
encodingConfig.TxConfig.TxDecoder(),
|
||||
baseAppOptions...,
|
||||
)
|
||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||
bApp.SetVersion(version.Version)
|
||||
bApp.SetInterfaceRegistry(interfaceRegistry)
|
||||
|
||||
keys := sdk.NewKVStoreKeys(
|
||||
// SDK keys
|
||||
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
|
||||
minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,
|
||||
govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey,
|
||||
govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey,
|
||||
evidencetypes.StoreKey, capabilitytypes.StoreKey,
|
||||
authzkeeper.StoreKey,
|
||||
feegrant.StoreKey, authzkeeper.StoreKey,
|
||||
// ibc keys
|
||||
ibchost.StoreKey, ibctransfertypes.StoreKey,
|
||||
// ethermint keys
|
||||
@@ -299,29 +310,9 @@ func NewEthermintApp(
|
||||
)
|
||||
|
||||
// Add the EVM transient store key
|
||||
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey)
|
||||
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey)
|
||||
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
|
||||
|
||||
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||
bApp := baseapp.NewBaseApp(
|
||||
appName,
|
||||
logger,
|
||||
db,
|
||||
encodingConfig.TxConfig.TxDecoder(),
|
||||
baseAppOptions...,
|
||||
)
|
||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||
bApp.SetVersion(version.Version)
|
||||
|
||||
evmtypes.RegisterInterfaces(interfaceRegistry)
|
||||
bApp.SetInterfaceRegistry(interfaceRegistry)
|
||||
|
||||
// configure state listening capabilities using AppOptions
|
||||
// we are doing nothing with the returned streamingServices and waitGroup in this case
|
||||
if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, keys); err != nil {
|
||||
tmos.Exit(err.Error())
|
||||
}
|
||||
|
||||
app := &EthermintApp{
|
||||
BaseApp: bApp,
|
||||
cdc: cdc,
|
||||
@@ -350,47 +341,96 @@ func NewEthermintApp(
|
||||
|
||||
// use custom Ethermint account for contracts
|
||||
app.AccountKeeper = authkeeper.NewAccountKeeper(
|
||||
appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), ethermint.ProtoAccount, maccPerms, sdk.Bech32MainPrefix,
|
||||
appCodec, keys[authtypes.StoreKey],
|
||||
app.GetSubspace(authtypes.ModuleName),
|
||||
ethermint.ProtoAccount,
|
||||
maccPerms,
|
||||
sdk.GetConfig().GetBech32AccountAddrPrefix(),
|
||||
)
|
||||
app.BankKeeper = bankkeeper.NewBaseKeeper(
|
||||
appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.BlockedAddrs(),
|
||||
appCodec,
|
||||
keys[banktypes.StoreKey],
|
||||
app.AccountKeeper,
|
||||
app.GetSubspace(banktypes.ModuleName),
|
||||
app.BlockedAddrs(),
|
||||
)
|
||||
stakingKeeper := stakingkeeper.NewKeeper(
|
||||
appCodec, keys[stakingtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.GetSubspace(stakingtypes.ModuleName),
|
||||
appCodec, keys[stakingtypes.StoreKey],
|
||||
app.AccountKeeper,
|
||||
app.BankKeeper,
|
||||
app.GetSubspace(stakingtypes.ModuleName),
|
||||
)
|
||||
app.MintKeeper = mintkeeper.NewKeeper(
|
||||
appCodec, keys[minttypes.StoreKey], app.GetSubspace(minttypes.ModuleName), &stakingKeeper,
|
||||
app.AccountKeeper, app.BankKeeper, authtypes.FeeCollectorName,
|
||||
appCodec,
|
||||
keys[minttypes.StoreKey],
|
||||
app.GetSubspace(minttypes.ModuleName),
|
||||
&stakingKeeper,
|
||||
app.AccountKeeper,
|
||||
app.BankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
)
|
||||
app.DistrKeeper = distrkeeper.NewKeeper(
|
||||
appCodec, keys[distrtypes.StoreKey], app.GetSubspace(distrtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
|
||||
&stakingKeeper, authtypes.FeeCollectorName,
|
||||
appCodec,
|
||||
keys[distrtypes.StoreKey],
|
||||
app.GetSubspace(distrtypes.ModuleName),
|
||||
app.AccountKeeper,
|
||||
app.BankKeeper,
|
||||
&stakingKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
)
|
||||
app.SlashingKeeper = slashingkeeper.NewKeeper(
|
||||
appCodec, keys[slashingtypes.StoreKey], &stakingKeeper, app.GetSubspace(slashingtypes.ModuleName),
|
||||
appCodec,
|
||||
keys[slashingtypes.StoreKey],
|
||||
&stakingKeeper,
|
||||
app.GetSubspace(slashingtypes.ModuleName),
|
||||
)
|
||||
app.CrisisKeeper = crisiskeeper.NewKeeper(
|
||||
app.GetSubspace(crisistypes.ModuleName), invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName,
|
||||
app.GetSubspace(crisistypes.ModuleName),
|
||||
invCheckPeriod,
|
||||
app.BankKeeper,
|
||||
authtypes.FeeCollectorName,
|
||||
)
|
||||
app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper)
|
||||
app.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp, authtypes.NewModuleAddress(govtypes.ModuleName).String())
|
||||
app.FeeGrantKeeper = feegrantkeeper.NewKeeper(
|
||||
appCodec,
|
||||
keys[feegrant.StoreKey],
|
||||
app.AccountKeeper)
|
||||
|
||||
// set the governance module account as the authority for conducting upgrades
|
||||
app.UpgradeKeeper = upgradekeeper.NewKeeper(
|
||||
skipUpgradeHeights,
|
||||
keys[upgradetypes.StoreKey],
|
||||
appCodec,
|
||||
homePath,
|
||||
app.BaseApp,
|
||||
authtypes.NewModuleAddress(govtypes.ModuleName).String())
|
||||
|
||||
// register the staking hooks
|
||||
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
|
||||
app.StakingKeeper = *stakingKeeper.SetHooks(
|
||||
stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()),
|
||||
stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(),
|
||||
app.SlashingKeeper.Hooks()),
|
||||
)
|
||||
|
||||
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.MsgServiceRouter(), app.AccountKeeper)
|
||||
app.AuthzKeeper = authzkeeper.NewKeeper(
|
||||
keys[authzkeeper.StoreKey],
|
||||
appCodec,
|
||||
app.MsgServiceRouter(),
|
||||
app.AccountKeeper)
|
||||
|
||||
tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer))
|
||||
|
||||
// Create Ethermint keepers
|
||||
app.FeeMarketKeeper = feemarketkeeper.NewKeeper(
|
||||
appCodec, keys[feemarkettypes.StoreKey], app.GetSubspace(feemarkettypes.ModuleName),
|
||||
appCodec, app.GetSubspace(feemarkettypes.ModuleName), keys[feemarkettypes.StoreKey], tkeys[feemarkettypes.TransientKey],
|
||||
)
|
||||
|
||||
// Create Cerc-io laconic keepers
|
||||
app.EvmKeeper = evmkeeper.NewKeeper(
|
||||
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
|
||||
app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper,
|
||||
nil, geth.NewEVM, tracer,
|
||||
)
|
||||
|
||||
// Create laconic keepers
|
||||
app.AuctionKeeper = auctionkeeper.NewKeeper(
|
||||
app.AccountKeeper, app.BankKeeper, keys[auctiontypes.StoreKey],
|
||||
appCodec, app.GetSubspace(auctiontypes.ModuleName),
|
||||
@@ -411,12 +451,6 @@ func NewEthermintApp(
|
||||
keys[nameservicetypes.StoreKey], app.GetSubspace(nameservicetypes.ModuleName),
|
||||
)
|
||||
|
||||
app.EvmKeeper = evmkeeper.NewKeeper(
|
||||
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName),
|
||||
app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper,
|
||||
tracer,
|
||||
)
|
||||
|
||||
// Create IBC Keeper
|
||||
app.IBCKeeper = ibckeeper.NewKeeper(
|
||||
appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper,
|
||||
@@ -429,13 +463,11 @@ func NewEthermintApp(
|
||||
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
|
||||
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
|
||||
AddRoute(ibchost.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper))
|
||||
|
||||
govConfig := govtypes.DefaultConfig()
|
||||
/*
|
||||
Example of setting gov params:
|
||||
govConfig.MaxMetadataLen = 10000
|
||||
*/
|
||||
|
||||
govKeeper := govkeeper.NewKeeper(
|
||||
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
|
||||
&stakingKeeper, govRouter, app.MsgServiceRouter(), govConfig,
|
||||
@@ -456,7 +488,7 @@ func NewEthermintApp(
|
||||
transferModule := transfer.NewAppModule(app.TransferKeeper)
|
||||
transferIBCModule := transfer.NewIBCModule(app.TransferKeeper)
|
||||
|
||||
//Create static IBC router, add transfer route, then set and seal it
|
||||
// Create static IBC router, add transfer route, then set and seal it
|
||||
ibcRouter := porttypes.NewRouter()
|
||||
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule)
|
||||
app.IBCKeeper.SetRouter(ibcRouter)
|
||||
@@ -487,6 +519,7 @@ func NewEthermintApp(
|
||||
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
|
||||
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
|
||||
crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants),
|
||||
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
|
||||
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
|
||||
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
@@ -495,8 +528,8 @@ func NewEthermintApp(
|
||||
upgrade.NewAppModule(app.UpgradeKeeper),
|
||||
evidence.NewAppModule(app.EvidenceKeeper),
|
||||
params.NewAppModule(app.ParamsKeeper),
|
||||
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
|
||||
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
|
||||
|
||||
// ibc modules
|
||||
ibc.NewAppModule(app.IBCKeeper),
|
||||
transferModule,
|
||||
@@ -513,7 +546,7 @@ func NewEthermintApp(
|
||||
// there is nothing left over in the validator fee pool, so as to keep the
|
||||
// CanWithdrawInvariant invariant.
|
||||
// NOTE: upgrade module must go first to handle software upgrades.
|
||||
// NOTE: staking module is required if HistoricalEntries param > 0.
|
||||
// NOTE: staking module is required if HistoricalEntries param > 0
|
||||
// NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC)
|
||||
app.mm.SetOrderBeginBlockers(
|
||||
upgradetypes.ModuleName,
|
||||
@@ -574,6 +607,7 @@ func NewEthermintApp(
|
||||
|
||||
// NOTE: The genutils module must occur after staking so that pools are
|
||||
// properly initialized with tokens from genesis accounts.
|
||||
// NOTE: The genutils module must also occur after auth so that it can access the params from auth.
|
||||
// NOTE: Capability module must occur first so that it can initialize any capabilities
|
||||
// so that other modules that want to create or claim capabilities afterwards in InitChain
|
||||
// can do so safely.
|
||||
@@ -588,6 +622,11 @@ func NewEthermintApp(
|
||||
govtypes.ModuleName,
|
||||
minttypes.ModuleName,
|
||||
ibchost.ModuleName,
|
||||
// evm module denomination is used by the feemarket module, in AnteHandle
|
||||
evmtypes.ModuleName,
|
||||
// NOTE: feemarket need to be initialized before genutil module:
|
||||
// gentx transactions use MinGasPriceDecorator.AnteHandle
|
||||
feemarkettypes.ModuleName,
|
||||
genutiltypes.ModuleName,
|
||||
evidencetypes.ModuleName,
|
||||
ibctransfertypes.ModuleName,
|
||||
@@ -596,48 +635,37 @@ func NewEthermintApp(
|
||||
paramstypes.ModuleName,
|
||||
upgradetypes.ModuleName,
|
||||
vestingtypes.ModuleName,
|
||||
// Ethermint modules
|
||||
evmtypes.ModuleName,
|
||||
feemarkettypes.ModuleName,
|
||||
// laconic modules
|
||||
auctiontypes.ModuleName,
|
||||
bondtypes.ModuleName,
|
||||
nameservicetypes.ModuleName,
|
||||
|
||||
// NOTE: crisis module must go at the end to check for invariants on each module
|
||||
crisistypes.ModuleName,
|
||||
)
|
||||
|
||||
// Uncomment if you want to set a custom migration order here.
|
||||
// app.mm.SetOrderMigrations(custom order)
|
||||
|
||||
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
||||
app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino)
|
||||
app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())
|
||||
app.mm.RegisterServices(app.configurator)
|
||||
|
||||
// RegisterUpgradeHandlers is used for registering any on-chain upgrades.
|
||||
// Make sure it's called after `app.mm` and `app.configurator` are set.
|
||||
app.RegisterUpgradeHandlers()
|
||||
|
||||
// add test gRPC service for testing gRPC queries in isolation
|
||||
// testdata.RegisterTestServiceServer(app.GRPCQueryRouter(), testdata.TestServiceImpl{})
|
||||
|
||||
// create the simulation manager and define the order of the modules for deterministic simulations
|
||||
|
||||
//
|
||||
// NOTE: this is not required apps that don't use the simulator for fuzz testing
|
||||
// transactions
|
||||
app.sm = module.NewSimulationManager(
|
||||
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
|
||||
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
|
||||
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
|
||||
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
|
||||
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
params.NewAppModule(app.ParamsKeeper),
|
||||
evidence.NewAppModule(app.EvidenceKeeper),
|
||||
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
|
||||
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
|
||||
ibc.NewAppModule(app.IBCKeeper),
|
||||
transferModule,
|
||||
evm.NewAppModule(app.EvmKeeper, app.AccountKeeper),
|
||||
feemarket.NewAppModule(app.FeeMarketKeeper),
|
||||
)
|
||||
overrideModules := map[string]module.AppModuleSimulation{
|
||||
authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
|
||||
}
|
||||
app.sm = module.NewSimulationManagerFromAppModules(app.mm.Modules, overrideModules)
|
||||
|
||||
app.sm.RegisterStoreDecoders()
|
||||
|
||||
@@ -649,31 +677,22 @@ func NewEthermintApp(
|
||||
// initialize BaseApp
|
||||
app.SetInitChainer(app.InitChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
|
||||
// use Ethermint's custom AnteHandler
|
||||
|
||||
maxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted))
|
||||
options := ante.HandlerOptions{
|
||||
AccountKeeper: app.AccountKeeper,
|
||||
BankKeeper: app.BankKeeper,
|
||||
EvmKeeper: app.EvmKeeper,
|
||||
FeegrantKeeper: app.FeeGrantKeeper,
|
||||
IBCKeeper: app.IBCKeeper,
|
||||
FeeMarketKeeper: app.FeeMarketKeeper,
|
||||
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
MaxTxGasWanted: maxGasWanted,
|
||||
}
|
||||
|
||||
if err := options.Validate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app.SetAnteHandler(ante.NewAnteHandler(options))
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
|
||||
app.ScopedIBCKeeper = scopedIBCKeeper
|
||||
app.ScopedTransferKeeper = scopedTransferKeeper
|
||||
app.setAnteHandler(encodingConfig.TxConfig, cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted)))
|
||||
// In v0.46, the SDK introduces _postHandlers_. PostHandlers are like
|
||||
// antehandlers, but are run _after_ the `runMsgs` execution. They are also
|
||||
// defined as a chain, and have the same signature as antehandlers.
|
||||
//
|
||||
// In baseapp, postHandlers are run in the same store branch as `runMsgs`,
|
||||
// meaning that both `runMsgs` and `postHandler` state will be committed if
|
||||
// both are successful, and both will be reverted if any of the two fails.
|
||||
//
|
||||
// The SDK exposes a default empty postHandlers chain.
|
||||
//
|
||||
// Please note that changing any of the anteHandler or postHandler chain is
|
||||
// likely to be a state-machine breaking change, which needs a coordinated
|
||||
// upgrade.
|
||||
app.setPostHandler()
|
||||
|
||||
if loadLatest {
|
||||
if err := app.LoadLatestVersion(); err != nil {
|
||||
@@ -681,9 +700,43 @@ func NewEthermintApp(
|
||||
}
|
||||
}
|
||||
|
||||
app.ScopedIBCKeeper = scopedIBCKeeper
|
||||
app.ScopedTransferKeeper = scopedTransferKeeper
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// use Ethermint's custom AnteHandler
|
||||
func (app *EthermintApp) setAnteHandler(txConfig client.TxConfig, maxGasWanted uint64) {
|
||||
anteHandler, err := ante.NewAnteHandler(ante.HandlerOptions{
|
||||
AccountKeeper: app.AccountKeeper,
|
||||
BankKeeper: app.BankKeeper,
|
||||
SignModeHandler: txConfig.SignModeHandler(),
|
||||
FeegrantKeeper: app.FeeGrantKeeper,
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
IBCKeeper: app.IBCKeeper,
|
||||
EvmKeeper: app.EvmKeeper,
|
||||
FeeMarketKeeper: app.FeeMarketKeeper,
|
||||
MaxTxGasWanted: maxGasWanted,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app.SetAnteHandler(anteHandler)
|
||||
}
|
||||
|
||||
func (app *EthermintApp) setPostHandler() {
|
||||
postHandler, err := posthandler.NewPostHandler(
|
||||
posthandler.HandlerOptions{},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app.SetPostHandler(postHandler)
|
||||
}
|
||||
|
||||
// Name returns the name of the App
|
||||
func (app *EthermintApp) Name() string { return app.BaseApp.Name() }
|
||||
|
||||
@@ -709,8 +762,7 @@ func (app *EthermintApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain)
|
||||
|
||||
// LoadHeight loads state at a particular height
|
||||
func (app *EthermintApp) LoadHeight(height int64) error {
|
||||
// return app.LoadVersion(height)
|
||||
return nil
|
||||
return app.LoadVersion(height)
|
||||
}
|
||||
|
||||
// ModuleAccountAddrs returns all the app's module account addresses.
|
||||
@@ -793,16 +845,12 @@ func (app *EthermintApp) SimulationManager() *module.SimulationManager {
|
||||
// API server.
|
||||
func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
|
||||
clientCtx := apiSvr.ClientCtx
|
||||
// NOTE: in v0.46 legacy routes are removed
|
||||
// rpc.RegisterRoutes(clientCtx, apiSvr.Router)
|
||||
// evmrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
|
||||
|
||||
// Register new tx routes from grpc-gateway.
|
||||
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||
// Register new tendermint queries routes from grpc-gateway.
|
||||
tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||
|
||||
// Register grpc-gateway routes for all modules.
|
||||
// Register grpc-gateway routes for all modules.
|
||||
ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
|
||||
|
||||
// register swagger API from root so that other applications can override easily
|
||||
@@ -811,10 +859,12 @@ func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterTxService implements the Application.RegisterTxService method.
|
||||
func (app *EthermintApp) RegisterTxService(clientCtx client.Context) {
|
||||
authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
|
||||
}
|
||||
|
||||
// RegisterTendermintService implements the Application.RegisterTendermintService method.
|
||||
func (app *EthermintApp) RegisterTendermintService(clientCtx client.Context) {
|
||||
tmservice.RegisterTendermintService(
|
||||
clientCtx,
|
||||
@@ -841,14 +891,11 @@ func GetMaccPerms() map[string][]string {
|
||||
for k, v := range maccPerms {
|
||||
dupMaccPerms[k] = v
|
||||
}
|
||||
|
||||
return dupMaccPerms
|
||||
}
|
||||
|
||||
// initParamsKeeper init params keeper and its subspaces
|
||||
func initParamsKeeper(
|
||||
appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey,
|
||||
) paramskeeper.Keeper {
|
||||
func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper {
|
||||
paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)
|
||||
|
||||
// SDK subspaces
|
||||
|
||||
+5
-25
@@ -4,43 +4,23 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
)
|
||||
|
||||
func TestEthermintAppExport(t *testing.T) {
|
||||
encCfg := encoding.MakeConfig(ModuleBasics)
|
||||
db := dbm.NewMemDB()
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
app := NewTestAppWithCustomOptions(t, false, SetupOptions{
|
||||
Logger: logger,
|
||||
DB: db,
|
||||
InvCheckPeriod: 0,
|
||||
EncConfig: encCfg,
|
||||
HomePath: DefaultNodeHome,
|
||||
SkipUpgradeHeights: map[int64]bool{},
|
||||
AppOpts: EmptyAppOptions{},
|
||||
})
|
||||
|
||||
for acc := range allowedReceivingModAcc {
|
||||
// check module account is not blocked in bank
|
||||
require.False(
|
||||
t,
|
||||
app.BankKeeper.BlockedAddr(app.AccountKeeper.GetModuleAddress(acc)),
|
||||
"ensure that blocked addresses %s are properly set in bank keeper",
|
||||
)
|
||||
}
|
||||
|
||||
app := SetupWithDB(false, nil, db)
|
||||
app.Commit()
|
||||
logger2 := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
|
||||
// Making a new app object with the db, so that initchain hasn't been called
|
||||
app2 := NewEthermintApp(logger2, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
|
||||
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
_, err := app2.ExportAppStateAndValidators(false, []string{})
|
||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
@@ -14,11 +14,9 @@ import (
|
||||
|
||||
func BenchmarkEthermintApp_ExportAppStateAndValidators(b *testing.B) {
|
||||
db := dbm.NewMemDB()
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
app := NewEthermintApp(log.NewTMLogger(io.Discard), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
|
||||
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
|
||||
genesisState := NewDefaultGenesisState(app.appCodec)
|
||||
genesisState := NewTestGenesisState(app.AppCodec())
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
@@ -38,7 +36,7 @@ func BenchmarkEthermintApp_ExportAppStateAndValidators(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Making a new app object with the db, so that initchain hasn't been called
|
||||
app2 := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(io.Discard)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
if _, err := app2.ExportAppStateAndValidators(false, []string{}); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
+15
-7
@@ -6,18 +6,20 @@ import (
|
||||
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
servertypes "github.com/cosmos/cosmos-sdk/server/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
)
|
||||
|
||||
// NewDefaultGenesisState generates the default state for the application.
|
||||
func NewDefaultGenesisState(cdc codec.JSONCodec) simapp.GenesisState {
|
||||
return ModuleBasics.DefaultGenesis(cdc)
|
||||
func NewDefaultGenesisState() simapp.GenesisState {
|
||||
encCfg := encoding.MakeConfig(ModuleBasics)
|
||||
return ModuleBasics.DefaultGenesis(encCfg.Codec)
|
||||
}
|
||||
|
||||
// ExportAppStateAndValidators exports the state of the application for a genesis
|
||||
@@ -60,7 +62,7 @@ func (app *EthermintApp) ExportAppStateAndValidators(
|
||||
|
||||
// prepare for fresh start at zero height
|
||||
// NOTE zero height genesis is a temporary feature which will be deprecated
|
||||
// in favor of export at a block height
|
||||
// in favor of export at a block height
|
||||
func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) error {
|
||||
applyAllowedAddrs := false
|
||||
|
||||
@@ -123,7 +125,9 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAd
|
||||
feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
|
||||
app.DistrKeeper.SetFeePool(ctx, feePool)
|
||||
|
||||
app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
|
||||
if err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()); err != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -137,8 +141,12 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAd
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr)
|
||||
app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr)
|
||||
if err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// reset context height
|
||||
|
||||
+82
-31
@@ -6,17 +6,22 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/app/ante"
|
||||
evmenc "github.com/cerc-io/laconicd/encoding"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/simapp/params"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
||||
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||
@@ -27,9 +32,6 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
evmenc "github.com/cerc-io/laconicd/encoding"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
|
||||
ibchost "github.com/cosmos/ibc-go/v5/modules/core/24-host"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
@@ -61,9 +63,34 @@ func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
|
||||
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
|
||||
// inter-block write-through cache.
|
||||
// TODO: implement this cache as enhancement to v2 multistore
|
||||
func interBlockCacheOpt() func(*baseapp.BaseApp) {
|
||||
return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager())
|
||||
}
|
||||
@@ -75,21 +102,24 @@ func TestFullAppSimulation(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
config.ChainID = SimAppChainID
|
||||
|
||||
defer func() {
|
||||
db.Close()
|
||||
require.NoError(t, db.Close())
|
||||
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.NoError(t, err)
|
||||
|
||||
// run randomized simulation
|
||||
_, simParams, simErr := simulation.SimulateFromSeed(
|
||||
t,
|
||||
os.Stdout,
|
||||
app.BaseApp,
|
||||
simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
StateFn(app.AppCodec(), app.SimulationManager()),
|
||||
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
simapp.SimulationOperations(app, app.AppCodec(), config),
|
||||
app.ModuleAccountAddrs(),
|
||||
config,
|
||||
@@ -113,12 +143,14 @@ func TestAppImportExport(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
config.ChainID = SimAppChainID
|
||||
|
||||
defer func() {
|
||||
db.Close()
|
||||
require.NoError(t, db.Close())
|
||||
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.NoError(t, err)
|
||||
require.Equal(t, appName, app.Name())
|
||||
|
||||
// Run randomized simulation
|
||||
@@ -126,8 +158,8 @@ func TestAppImportExport(t *testing.T) {
|
||||
t,
|
||||
os.Stdout,
|
||||
app.BaseApp,
|
||||
simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
StateFn(app.AppCodec(), app.SimulationManager()),
|
||||
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
simapp.SimulationOperations(app, app.AppCodec(), config),
|
||||
app.ModuleAccountAddrs(),
|
||||
config,
|
||||
@@ -150,24 +182,36 @@ func TestAppImportExport(t *testing.T) {
|
||||
|
||||
fmt.Printf("importing genesis...\n")
|
||||
|
||||
// nolint: dogsled
|
||||
//nolint: dogsled
|
||||
_, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
defer func() {
|
||||
newDB.Close()
|
||||
require.NoError(t, newDB.Close())
|
||||
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.NoError(t, err)
|
||||
|
||||
var genesisState simapp.GenesisState
|
||||
err = json.Unmarshal(exported.AppState, &genesisState)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctxA := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
|
||||
ctxB := newApp.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err := fmt.Sprintf("%v", r)
|
||||
if !strings.Contains(err, "validator set is empty after InitGenesis") {
|
||||
panic(r)
|
||||
}
|
||||
logger.Info("Skipping simulation as all validators have been unbonded")
|
||||
logger.Info("err", err, "stacktrace", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
ctxA := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight(), ChainID: SimAppChainID})
|
||||
ctxB := newApp.NewContext(true, tmproto.Header{Height: app.LastBlockHeight(), ChainID: SimAppChainID})
|
||||
newApp.mm.InitGenesis(ctxB, app.AppCodec(), genesisState)
|
||||
newApp.StoreConsensusParams(ctxB, exported.ConsensusParams)
|
||||
|
||||
@@ -190,6 +234,7 @@ func TestAppImportExport(t *testing.T) {
|
||||
{app.keys[govtypes.StoreKey], newApp.keys[govtypes.StoreKey], [][]byte{}},
|
||||
{app.keys[evidencetypes.StoreKey], newApp.keys[evidencetypes.StoreKey], [][]byte{}},
|
||||
{app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}},
|
||||
{app.keys[authzkeeper.StoreKey], newApp.keys[authzkeeper.StoreKey], [][]byte{authzkeeper.GrantKey, authzkeeper.GrantQueuePrefix}},
|
||||
{app.keys[ibchost.StoreKey], newApp.keys[ibchost.StoreKey], [][]byte{}},
|
||||
{app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}},
|
||||
}
|
||||
@@ -213,21 +258,24 @@ func TestAppSimulationAfterImport(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
config.ChainID = SimAppChainID
|
||||
|
||||
defer func() {
|
||||
db.Close()
|
||||
require.NoError(t, db.Close())
|
||||
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.NoError(t, err)
|
||||
|
||||
// Run randomized simulation
|
||||
stopEarly, simParams, simErr := simulation.SimulateFromSeed(
|
||||
t,
|
||||
os.Stdout,
|
||||
app.BaseApp,
|
||||
simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
StateFn(app.AppCodec(), app.SimulationManager()),
|
||||
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
simapp.SimulationOperations(app, app.AppCodec(), config),
|
||||
app.ModuleAccountAddrs(),
|
||||
config,
|
||||
@@ -259,14 +307,16 @@ func TestAppSimulationAfterImport(t *testing.T) {
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
defer func() {
|
||||
newDB.Close()
|
||||
require.NoError(t, newDB.Close())
|
||||
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.NoError(t, err)
|
||||
|
||||
newApp.InitChain(abci.RequestInitChain{
|
||||
ChainId: SimAppChainID,
|
||||
AppStateBytes: exported.AppState,
|
||||
})
|
||||
|
||||
@@ -274,8 +324,8 @@ func TestAppSimulationAfterImport(t *testing.T) {
|
||||
t,
|
||||
os.Stdout,
|
||||
newApp.BaseApp,
|
||||
simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
StateFn(app.AppCodec(), app.SimulationManager()),
|
||||
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
simapp.SimulationOperations(newApp, newApp.AppCodec(), config),
|
||||
app.ModuleAccountAddrs(),
|
||||
config,
|
||||
@@ -314,19 +364,20 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||
}
|
||||
|
||||
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(
|
||||
"running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
|
||||
config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
|
||||
)
|
||||
|
||||
_, _, err := simulation.SimulateFromSeed(
|
||||
_, _, err = simulation.SimulateFromSeed(
|
||||
t,
|
||||
os.Stdout,
|
||||
app.BaseApp,
|
||||
simapp.AppStateFn(app.AppCodec(), app.SimulationManager()),
|
||||
simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
StateFn(app.AppCodec(), app.SimulationManager()),
|
||||
RandomAccounts, // Replace with own random account function if using keys other than secp256k1
|
||||
simapp.SimulationOperations(app, app.AppCodec(), config),
|
||||
app.ModuleAccountAddrs(),
|
||||
config,
|
||||
|
||||
@@ -1,284 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
tmjson "github.com/tendermint/tendermint/libs/json"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/simapp/params"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/mock"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
)
|
||||
|
||||
// GenesisState of the blockchain is represented here as a map of raw json
|
||||
// messages key'd by a identifier string.
|
||||
// The identifier is used to determine which module genesis information belongs
|
||||
// to so it may be appropriately routed during init chain.
|
||||
// Within this application default genesis information is retrieved from
|
||||
// the ModuleBasicManager which populates json from each BasicModule
|
||||
// object provided to it during init.
|
||||
|
||||
// DefaultConsensusParams defines the default Tendermint consensus params used in
|
||||
// EthermintApp testing.
|
||||
var DefaultConsensusParams = &abci.ConsensusParams{
|
||||
Block: &abci.BlockParams{
|
||||
MaxBytes: 200000,
|
||||
MaxGas: -1, // no limit
|
||||
},
|
||||
Evidence: &tmproto.EvidenceParams{
|
||||
MaxAgeNumBlocks: 302400,
|
||||
MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration
|
||||
MaxBytes: 10000,
|
||||
},
|
||||
Validator: &tmproto.ValidatorParams{
|
||||
PubKeyTypes: []string{
|
||||
tmtypes.ABCIPubKeyTypeEd25519,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// SetupOptions defines arguments that are passed into `Simapp` constructor.
|
||||
type SetupOptions struct {
|
||||
Logger log.Logger
|
||||
DB dbm.DB
|
||||
InvCheckPeriod uint
|
||||
HomePath string
|
||||
SkipUpgradeHeights map[int64]bool
|
||||
EncConfig params.EncodingConfig
|
||||
AppOpts types.AppOptions
|
||||
}
|
||||
|
||||
func NewTestAppWithCustomOptions(t *testing.T, isCheckTx bool, options SetupOptions) *EthermintApp {
|
||||
t.Helper()
|
||||
|
||||
privVal := mock.NewPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
// create validator set with single validator
|
||||
validator := tmtypes.NewValidator(pubKey, 1)
|
||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
||||
|
||||
// generate genesis account
|
||||
priv, err := ethsecp256k1.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
|
||||
|
||||
acc := ðermint.EthAccount{
|
||||
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0),
|
||||
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
|
||||
}
|
||||
|
||||
balance := banktypes.Balance{
|
||||
Address: acc.GetAddress().String(),
|
||||
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
|
||||
}
|
||||
|
||||
app := NewEthermintApp(options.Logger, options.DB, nil, true, options.SkipUpgradeHeights, options.HomePath, options.InvCheckPeriod, options.EncConfig, options.AppOpts)
|
||||
genesisState := NewDefaultGenesisState(app.appCodec)
|
||||
genesisState = genesisStateWithValSet(t, app, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
|
||||
|
||||
if !isCheckTx {
|
||||
// init chain must be called to stop deliverState from being nil
|
||||
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Initialize the chain
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
ChainId: "ethermint_9000-1",
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
ConsensusParams: DefaultConsensusParams,
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
||||
func Setup(t *testing.T, isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState) *EthermintApp {
|
||||
|
||||
t.Helper()
|
||||
|
||||
privVal := mock.NewPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
// create validator set with single validator
|
||||
validator := tmtypes.NewValidator(pubKey, 1)
|
||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
||||
|
||||
priv, err := ethsecp256k1.GenerateKey()
|
||||
require.NoError(t, err)
|
||||
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
|
||||
|
||||
acc := ðermint.EthAccount{
|
||||
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0),
|
||||
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
|
||||
}
|
||||
|
||||
balance := banktypes.Balance{
|
||||
Address: acc.GetAddress().String(),
|
||||
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
|
||||
}
|
||||
|
||||
app := SetupWithGenesisValSet(t, valSet, patchGenesis, []authtypes.GenesisAccount{acc}, balance)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func setup(withGenesis bool, invCheckPeriod uint, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState) (*EthermintApp, simapp.GenesisState) {
|
||||
encCdc := encoding.MakeConfig(ModuleBasics)
|
||||
app := NewEthermintApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, encCdc, EmptyAppOptions{})
|
||||
if withGenesis {
|
||||
genesisState := NewDefaultGenesisState(encCdc.Codec)
|
||||
if patchGenesis != nil {
|
||||
genesisState = patchGenesis(app, genesisState)
|
||||
}
|
||||
return app, genesisState
|
||||
}
|
||||
|
||||
return app, simapp.GenesisState{}
|
||||
}
|
||||
|
||||
// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts
|
||||
// that also act as delegators. For simplicity, each validator is bonded with a delegation
|
||||
// of one consensus engine unit in the default token of the simapp from first genesis
|
||||
// account. A Nop logger is set in SimApp.
|
||||
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *EthermintApp {
|
||||
t.Helper()
|
||||
|
||||
app, genesisState := setup(true, 5, patchGenesis)
|
||||
genesisState = genesisStateWithValSet(t, app, genesisState, valSet, genAccs, balances...)
|
||||
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
// init chain will set the validator set and initialize the genesis accounts
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
ChainId: "ethermint_9000-1",
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
ConsensusParams: DefaultConsensusParams,
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
|
||||
// commit genesis changes
|
||||
// app.Commit()
|
||||
// app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{
|
||||
// ChainID: "ethermint_9000-1",
|
||||
// Height: app.LastBlockHeight() + 1,
|
||||
// AppHash: app.LastCommitID().Hash,
|
||||
// ValidatorsHash: valSet.Hash(),
|
||||
// NextValidatorsHash: valSet.Hash(),
|
||||
// }})
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func genesisStateWithValSet(t *testing.T, app *EthermintApp, genesisState simapp.GenesisState,
|
||||
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) simapp.GenesisState {
|
||||
// set genesis accounts
|
||||
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
|
||||
genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)
|
||||
|
||||
validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
|
||||
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
|
||||
|
||||
bondAmt := sdk.DefaultPowerReduction
|
||||
|
||||
for _, val := range valSet.Validators {
|
||||
pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
|
||||
require.NoError(t, err)
|
||||
pkAny, err := codectypes.NewAnyWithValue(pk)
|
||||
require.NoError(t, err)
|
||||
validator := stakingtypes.Validator{
|
||||
OperatorAddress: sdk.ValAddress(val.Address).String(),
|
||||
ConsensusPubkey: pkAny,
|
||||
Jailed: false,
|
||||
Status: stakingtypes.Bonded,
|
||||
Tokens: bondAmt,
|
||||
DelegatorShares: sdk.OneDec(),
|
||||
Description: stakingtypes.Description{},
|
||||
UnbondingHeight: int64(0),
|
||||
UnbondingTime: time.Unix(0, 0).UTC(),
|
||||
Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
MinSelfDelegation: sdk.ZeroInt(),
|
||||
}
|
||||
validators = append(validators, validator)
|
||||
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
|
||||
|
||||
}
|
||||
// set validators and delegations
|
||||
stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
|
||||
genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis)
|
||||
|
||||
totalSupply := sdk.NewCoins()
|
||||
for _, b := range balances {
|
||||
// add genesis acc tokens to total supply
|
||||
totalSupply = totalSupply.Add(b.Coins...)
|
||||
}
|
||||
|
||||
for range delegations {
|
||||
// add delegated tokens to total supply
|
||||
totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))
|
||||
}
|
||||
|
||||
// add bonded amount to bonded pool module account
|
||||
balances = append(balances, banktypes.Balance{
|
||||
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
|
||||
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
|
||||
})
|
||||
|
||||
// update total supply
|
||||
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
|
||||
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
|
||||
|
||||
return genesisState
|
||||
}
|
||||
|
||||
// CreateRandomAccounts will generate random accounts
|
||||
func CreateRandomAccounts(accNum int) []sdk.AccAddress {
|
||||
// createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order.
|
||||
testAddrs := make([]sdk.AccAddress, accNum)
|
||||
for i := 0; i < accNum; i++ {
|
||||
pk := ed25519.GenPrivKey().PubKey()
|
||||
testAddrs[i] = sdk.AccAddress(pk.Address())
|
||||
}
|
||||
|
||||
return testAddrs
|
||||
}
|
||||
|
||||
// EmptyAppOptions is a stub implementing AppOptions
|
||||
type EmptyAppOptions struct{}
|
||||
|
||||
// Get implements AppOptions
|
||||
func (ao EmptyAppOptions) Get(o string) interface{} {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
|
||||
)
|
||||
|
||||
func (app *EthermintApp) RegisterUpgradeHandlers() {
|
||||
planName := "integration-test-upgrade"
|
||||
app.UpgradeKeeper.SetUpgradeHandler(planName, func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
|
||||
return app.mm.RunMigrations(ctx, app.configurator, fromVM)
|
||||
})
|
||||
}
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/mock"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
// DefaultConsensusParams defines the default Tendermint consensus params used in
|
||||
// EthermintApp testing.
|
||||
var DefaultConsensusParams = &abci.ConsensusParams{
|
||||
Block: &abci.BlockParams{
|
||||
MaxBytes: 200000,
|
||||
MaxGas: -1, // no limit
|
||||
},
|
||||
Evidence: &tmproto.EvidenceParams{
|
||||
MaxAgeNumBlocks: 302400,
|
||||
MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration
|
||||
MaxBytes: 10000,
|
||||
},
|
||||
Validator: &tmproto.ValidatorParams{
|
||||
PubKeyTypes: []string{
|
||||
tmtypes.ABCIPubKeyTypeEd25519,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
||||
func Setup(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState) *EthermintApp {
|
||||
return SetupWithDB(isCheckTx, patchGenesis, dbm.NewMemDB())
|
||||
}
|
||||
|
||||
// SetupWithDB initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
||||
func SetupWithDB(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState, db dbm.DB) *EthermintApp {
|
||||
app := NewEthermintApp(log.NewNopLogger(),
|
||||
db,
|
||||
nil,
|
||||
true,
|
||||
map[int64]bool{},
|
||||
DefaultNodeHome,
|
||||
5,
|
||||
encoding.MakeConfig(ModuleBasics),
|
||||
simapp.EmptyAppOptions{})
|
||||
if !isCheckTx {
|
||||
// init chain must be called to stop deliverState from being nil
|
||||
genesisState := NewTestGenesisState(app.AppCodec())
|
||||
if patchGenesis != nil {
|
||||
genesisState = patchGenesis(app, genesisState)
|
||||
}
|
||||
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Initialize the chain
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
ChainId: "ethermint_9000-1",
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
ConsensusParams: DefaultConsensusParams,
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// RandomGenesisAccounts is used by the auth module to create random genesis accounts in simulation when a genesis.json is not specified.
|
||||
// In contrast, the default auth module's RandomGenesisAccounts implementation creates only base accounts and vestings accounts.
|
||||
func RandomGenesisAccounts(simState *module.SimulationState) authtypes.GenesisAccounts {
|
||||
emptyCodeHash := crypto.Keccak256(nil)
|
||||
genesisAccs := make(authtypes.GenesisAccounts, len(simState.Accounts))
|
||||
for i, acc := range simState.Accounts {
|
||||
bacc := authtypes.NewBaseAccountWithAddress(acc.Address)
|
||||
|
||||
ethacc := ðermint.EthAccount{
|
||||
BaseAccount: bacc,
|
||||
CodeHash: common.BytesToHash(emptyCodeHash).String(),
|
||||
}
|
||||
genesisAccs[i] = ethacc
|
||||
}
|
||||
|
||||
return genesisAccs
|
||||
}
|
||||
|
||||
// RandomAccounts creates random accounts with an ethsecp256k1 private key
|
||||
// TODO: replace secp256k1.GenPrivKeyFromSecret() with similar function in go-ethereum
|
||||
func RandomAccounts(r *rand.Rand, n int) []simtypes.Account {
|
||||
accs := make([]simtypes.Account, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
// don't need that much entropy for simulation
|
||||
privkeySeed := make([]byte, 15)
|
||||
_, _ = r.Read(privkeySeed)
|
||||
|
||||
prv := secp256k1.GenPrivKeyFromSecret(privkeySeed)
|
||||
ethPrv := ðsecp256k1.PrivKey{}
|
||||
_ = ethPrv.UnmarshalAmino(prv.Bytes()) // UnmarshalAmino simply copies the bytes and assigns them to ethPrv.Key
|
||||
accs[i].PrivKey = ethPrv
|
||||
accs[i].PubKey = accs[i].PrivKey.PubKey()
|
||||
accs[i].Address = sdk.AccAddress(accs[i].PubKey.Address())
|
||||
|
||||
accs[i].ConsKey = ed25519.GenPrivKeyFromSecret(privkeySeed)
|
||||
}
|
||||
|
||||
return accs
|
||||
}
|
||||
|
||||
// StateFn returns the initial application state using a genesis or the simulation parameters.
|
||||
// It is a wrapper of simapp.AppStateFn to replace evm param EvmDenom with staking param BondDenom.
|
||||
func StateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) simtypes.AppStateFn {
|
||||
return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config,
|
||||
) (appState json.RawMessage, simAccs []simtypes.Account, chainID string, genesisTimestamp time.Time) {
|
||||
appStateFn := simapp.AppStateFn(cdc, simManager)
|
||||
appState, simAccs, chainID, genesisTimestamp = appStateFn(r, accs, config)
|
||||
|
||||
rawState := make(map[string]json.RawMessage)
|
||||
err := json.Unmarshal(appState, &rawState)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stakingStateBz, ok := rawState[stakingtypes.ModuleName]
|
||||
if !ok {
|
||||
panic("staking genesis state is missing")
|
||||
}
|
||||
|
||||
stakingState := new(stakingtypes.GenesisState)
|
||||
cdc.MustUnmarshalJSON(stakingStateBz, stakingState)
|
||||
|
||||
// we should get the BondDenom and make it the evmdenom.
|
||||
// thus simulation accounts could have positive amount of gas token.
|
||||
bondDenom := stakingState.Params.BondDenom
|
||||
|
||||
evmStateBz, ok := rawState[evmtypes.ModuleName]
|
||||
if !ok {
|
||||
panic("evm genesis state is missing")
|
||||
}
|
||||
|
||||
evmState := new(evmtypes.GenesisState)
|
||||
cdc.MustUnmarshalJSON(evmStateBz, evmState)
|
||||
|
||||
// we should replace the EvmDenom with BondDenom
|
||||
evmState.Params.EvmDenom = bondDenom
|
||||
|
||||
// change appState back
|
||||
rawState[evmtypes.ModuleName] = cdc.MustMarshalJSON(evmState)
|
||||
|
||||
// replace appstate
|
||||
appState, err = json.Marshal(rawState)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return appState, simAccs, chainID, genesisTimestamp
|
||||
}
|
||||
}
|
||||
|
||||
// NewTestGenesisState generate genesis state with single validator
|
||||
func NewTestGenesisState(codec codec.Codec) simapp.GenesisState {
|
||||
privVal := mock.NewPV()
|
||||
pubKey, err := privVal.GetPubKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// create validator set with single validator
|
||||
validator := tmtypes.NewValidator(pubKey, 1)
|
||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
||||
|
||||
// generate genesis account
|
||||
senderPrivKey := secp256k1.GenPrivKey()
|
||||
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
|
||||
balance := banktypes.Balance{
|
||||
Address: acc.GetAddress().String(),
|
||||
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
|
||||
}
|
||||
|
||||
genesisState := NewDefaultGenesisState()
|
||||
return genesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
|
||||
}
|
||||
|
||||
func genesisStateWithValSet(codec codec.Codec, genesisState simapp.GenesisState,
|
||||
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount,
|
||||
balances ...banktypes.Balance,
|
||||
) simapp.GenesisState {
|
||||
// set genesis accounts
|
||||
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
|
||||
genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis)
|
||||
|
||||
validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
|
||||
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
|
||||
|
||||
bondAmt := sdk.DefaultPowerReduction
|
||||
|
||||
for _, val := range valSet.Validators {
|
||||
pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pkAny, err := codectypes.NewAnyWithValue(pk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
validator := stakingtypes.Validator{
|
||||
OperatorAddress: sdk.ValAddress(val.Address).String(),
|
||||
ConsensusPubkey: pkAny,
|
||||
Jailed: false,
|
||||
Status: stakingtypes.Bonded,
|
||||
Tokens: bondAmt,
|
||||
DelegatorShares: sdk.OneDec(),
|
||||
Description: stakingtypes.Description{},
|
||||
UnbondingHeight: int64(0),
|
||||
UnbondingTime: time.Unix(0, 0).UTC(),
|
||||
Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
MinSelfDelegation: sdk.ZeroInt(),
|
||||
}
|
||||
validators = append(validators, validator)
|
||||
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
|
||||
}
|
||||
// set validators and delegations
|
||||
stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
|
||||
genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON(stakingGenesis)
|
||||
|
||||
totalSupply := sdk.NewCoins()
|
||||
for _, b := range balances {
|
||||
// add genesis acc tokens to total supply
|
||||
totalSupply = totalSupply.Add(b.Coins...)
|
||||
}
|
||||
|
||||
for range delegations {
|
||||
// add delegated tokens to total supply
|
||||
totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))
|
||||
}
|
||||
|
||||
// add bonded amount to bonded pool module account
|
||||
balances = append(balances, banktypes.Balance{
|
||||
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
|
||||
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
|
||||
})
|
||||
|
||||
// update total supply
|
||||
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
|
||||
genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis)
|
||||
|
||||
return genesisState
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
|
||||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
||||
ethermint "github.com/cerc-io/laconicd/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var (
|
||||
maxTestingAccounts = 100
|
||||
seed = int64(233)
|
||||
)
|
||||
|
||||
func TestRandomGenesisAccounts(t *testing.T) {
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
accs := RandomAccounts(r, rand.Intn(maxTestingAccounts))
|
||||
|
||||
encodingConfig := MakeEncodingConfig()
|
||||
appCodec := encodingConfig.Codec
|
||||
cdc := encodingConfig.Amino
|
||||
|
||||
paramsKeeper := initParamsKeeper(appCodec, cdc, sdk.NewKVStoreKey(paramstypes.StoreKey), sdk.NewTransientStoreKey(paramstypes.StoreKey))
|
||||
subSpace, find := paramsKeeper.GetSubspace(authtypes.ModuleName)
|
||||
require.True(t, find)
|
||||
accountKeeper := authkeeper.NewAccountKeeper(
|
||||
appCodec, sdk.NewKVStoreKey(authtypes.StoreKey), subSpace, ethermint.ProtoAccount, maccPerms, sdk.GetConfig().GetBech32AccountAddrPrefix(),
|
||||
)
|
||||
authModule := auth.NewAppModule(appCodec, accountKeeper, RandomGenesisAccounts)
|
||||
|
||||
genesisState := simapp.NewDefaultGenesisState(appCodec)
|
||||
simState := &module.SimulationState{Accounts: accs, Cdc: appCodec, Rand: r, GenState: genesisState}
|
||||
authModule.GenerateGenesisState(simState)
|
||||
|
||||
authStateBz, find := genesisState[authtypes.ModuleName]
|
||||
require.True(t, find)
|
||||
|
||||
authState := new(authtypes.GenesisState)
|
||||
appCodec.MustUnmarshalJSON(authStateBz, authState)
|
||||
accounts, err := authtypes.UnpackAccounts(authState.Accounts)
|
||||
require.NoError(t, err)
|
||||
for _, acc := range accounts {
|
||||
_, ok := acc.(ethermint.EthAccountI)
|
||||
require.True(t, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateFn(t *testing.T) {
|
||||
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
|
||||
if skip {
|
||||
t.Skip("skipping AppStateFn testing")
|
||||
}
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
config.ChainID = SimAppChainID
|
||||
config.Commit = true
|
||||
|
||||
defer func() {
|
||||
db.Close()
|
||||
require.NoError(t, os.RemoveAll(dir))
|
||||
}()
|
||||
|
||||
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, fauxMerkleModeOpt)
|
||||
require.Equal(t, appName, app.Name())
|
||||
|
||||
appStateFn := StateFn(app.AppCodec(), app.SimulationManager())
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
accounts := RandomAccounts(r, rand.Intn(maxTestingAccounts))
|
||||
appState, _, _, _ := appStateFn(r, accounts, config)
|
||||
|
||||
rawState := make(map[string]json.RawMessage)
|
||||
err = json.Unmarshal(appState, &rawState)
|
||||
require.NoError(t, err)
|
||||
|
||||
stakingStateBz, ok := rawState[stakingtypes.ModuleName]
|
||||
require.True(t, ok)
|
||||
|
||||
stakingState := new(stakingtypes.GenesisState)
|
||||
app.AppCodec().MustUnmarshalJSON(stakingStateBz, stakingState)
|
||||
bondDenom := stakingState.Params.BondDenom
|
||||
|
||||
evmStateBz, ok := rawState[evmtypes.ModuleName]
|
||||
require.True(t, ok)
|
||||
|
||||
evmState := new(evmtypes.GenesisState)
|
||||
app.AppCodec().MustUnmarshalJSON(evmStateBz, evmState)
|
||||
require.Equal(t, bondDenom, evmState.Params.EvmDenom)
|
||||
}
|
||||
|
||||
func TestRandomAccounts(t *testing.T) {
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
accounts := RandomAccounts(r, rand.Intn(maxTestingAccounts))
|
||||
for _, acc := range accounts {
|
||||
_, ok := acc.PrivKey.(*ethsecp256k1.PrivKey)
|
||||
require.True(t, ok)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user