test: add test cases for middleware
This commit is contained in:
parent
eb1af33649
commit
752fb3944f
24
app/app.go
24
app/app.go
@ -221,8 +221,8 @@ type EthermintApp struct {
|
|||||||
cdc *codec.LegacyAmino
|
cdc *codec.LegacyAmino
|
||||||
appCodec codec.Codec
|
appCodec codec.Codec
|
||||||
interfaceRegistry types.InterfaceRegistry
|
interfaceRegistry types.InterfaceRegistry
|
||||||
msgSvcRouter *authmiddleware.MsgServiceRouter
|
MsgSvcRouter *authmiddleware.MsgServiceRouter
|
||||||
legacyRouter sdk.Router
|
LegacyRouter sdk.Router
|
||||||
invCheckPeriod uint
|
invCheckPeriod uint
|
||||||
|
|
||||||
// keys to access the substores
|
// keys to access the substores
|
||||||
@ -368,8 +368,8 @@ func NewEthermintApp(
|
|||||||
appCodec: appCodec,
|
appCodec: appCodec,
|
||||||
interfaceRegistry: interfaceRegistry,
|
interfaceRegistry: interfaceRegistry,
|
||||||
invCheckPeriod: invCheckPeriod,
|
invCheckPeriod: invCheckPeriod,
|
||||||
legacyRouter: authmiddleware.NewLegacyRouter(),
|
LegacyRouter: authmiddleware.NewLegacyRouter(),
|
||||||
msgSvcRouter: authmiddleware.NewMsgServiceRouter(interfaceRegistry),
|
MsgSvcRouter: authmiddleware.NewMsgServiceRouter(interfaceRegistry),
|
||||||
keys: keys,
|
keys: keys,
|
||||||
tkeys: tkeys,
|
tkeys: tkeys,
|
||||||
memKeys: memKeys,
|
memKeys: memKeys,
|
||||||
@ -423,7 +423,7 @@ func NewEthermintApp(
|
|||||||
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.msgSvcRouter, app.AccountKeeper)
|
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.MsgSvcRouter, app.AccountKeeper)
|
||||||
|
|
||||||
tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer))
|
tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer))
|
||||||
|
|
||||||
@ -479,7 +479,7 @@ func NewEthermintApp(
|
|||||||
|
|
||||||
govKeeper := govkeeper.NewKeeper(
|
govKeeper := govkeeper.NewKeeper(
|
||||||
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
|
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
|
||||||
&stakingKeeper, govRouter, app.msgSvcRouter, govConfig,
|
&stakingKeeper, govRouter, app.MsgSvcRouter, govConfig,
|
||||||
)
|
)
|
||||||
|
|
||||||
app.GovKeeper = *govKeeper.SetHooks(
|
app.GovKeeper = *govKeeper.SetHooks(
|
||||||
@ -644,8 +644,8 @@ func NewEthermintApp(
|
|||||||
)
|
)
|
||||||
|
|
||||||
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
||||||
app.mm.RegisterRoutes(app.legacyRouter, app.QueryRouter(), encodingConfig.Amino)
|
app.mm.RegisterRoutes(app.LegacyRouter, app.QueryRouter(), encodingConfig.Amino)
|
||||||
app.configurator = module.NewConfigurator(app.appCodec, app.msgSvcRouter, app.GRPCQueryRouter())
|
app.configurator = module.NewConfigurator(app.appCodec, app.MsgSvcRouter, app.GRPCQueryRouter())
|
||||||
app.mm.RegisterServices(app.configurator)
|
app.mm.RegisterServices(app.configurator)
|
||||||
|
|
||||||
// add test gRPC service for testing gRPC queries in isolation
|
// add test gRPC service for testing gRPC queries in isolation
|
||||||
@ -685,8 +685,8 @@ func NewEthermintApp(
|
|||||||
options := middleware.HandlerOptions{
|
options := middleware.HandlerOptions{
|
||||||
Codec: app.appCodec,
|
Codec: app.appCodec,
|
||||||
Debug: app.Trace(),
|
Debug: app.Trace(),
|
||||||
LegacyRouter: app.legacyRouter,
|
LegacyRouter: app.LegacyRouter,
|
||||||
MsgServiceRouter: app.msgSvcRouter,
|
MsgServiceRouter: app.MsgSvcRouter,
|
||||||
AccountKeeper: app.AccountKeeper,
|
AccountKeeper: app.AccountKeeper,
|
||||||
BankKeeper: app.BankKeeper,
|
BankKeeper: app.BankKeeper,
|
||||||
EvmKeeper: app.EvmKeeper,
|
EvmKeeper: app.EvmKeeper,
|
||||||
@ -710,7 +710,9 @@ func (app *EthermintApp) setTxHandler(options middleware.HandlerOptions, txConfi
|
|||||||
indexEvents[e] = struct{}{}
|
indexEvents[e] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
txHandler, err := middleware.NewMiddleware(indexEventsStr, options)
|
options.IndexEvents = indexEvents
|
||||||
|
|
||||||
|
txHandler, err := middleware.NewMiddleware(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ func (vbd EthValidateBasicMiddleware) CheckTx(cx context.Context, req tx.Request
|
|||||||
|
|
||||||
// no need to validate basic on recheck tx, call next antehandler
|
// no need to validate basic on recheck tx, call next antehandler
|
||||||
if ctx.IsReCheckTx() {
|
if ctx.IsReCheckTx() {
|
||||||
return vbd.CheckTx(ctx, req, checkReq)
|
return vbd.next.CheckTx(ctx, req, checkReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := reqTx.ValidateBasic()
|
err := reqTx.ValidateBasic()
|
||||||
|
519
app/middleware/eth_test.go
Normal file
519
app/middleware/eth_test.go
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
package middleware_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth/middleware"
|
||||||
|
ante "github.com/tharsis/ethermint/app/middleware"
|
||||||
|
"github.com/tharsis/ethermint/server/config"
|
||||||
|
"github.com/tharsis/ethermint/tests"
|
||||||
|
"github.com/tharsis/ethermint/x/evm/statedb"
|
||||||
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
|
|
||||||
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func nextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
|
||||||
|
return ctx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestEthSigVerificationDecorator() {
|
||||||
|
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthSigVerificationMiddleware(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)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
err := signedTx.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
tx sdk.Tx
|
||||||
|
reCheckTx bool
|
||||||
|
expPass bool
|
||||||
|
}{
|
||||||
|
{"ReCheckTx", &invalidTx{}, true, false},
|
||||||
|
{"invalid transaction type", &invalidTx{}, false, false},
|
||||||
|
{
|
||||||
|
"invalid sender",
|
||||||
|
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &addr, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{"successful signature verification", signedTx, false, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestNewEthAccountVerificationDecorator() {
|
||||||
|
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthAccountVerificationMiddleware(
|
||||||
|
suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.EvmKeeper,
|
||||||
|
))
|
||||||
|
|
||||||
|
addr := tests.GenerateAddress()
|
||||||
|
|
||||||
|
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
tx.From = addr.Hex()
|
||||||
|
|
||||||
|
var vmdb *statedb.StateDB
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
tx sdk.Tx
|
||||||
|
malleate func()
|
||||||
|
checkTx bool
|
||||||
|
expPass bool
|
||||||
|
}{
|
||||||
|
{"not CheckTx", nil, func() {}, false, true},
|
||||||
|
{"invalid transaction type", &invalidTx{}, func() {}, true, false},
|
||||||
|
{
|
||||||
|
"sender not set to msg",
|
||||||
|
evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||||
|
func() {},
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sender not EOA",
|
||||||
|
tx,
|
||||||
|
func() {
|
||||||
|
// set not as an EOA
|
||||||
|
vmdb.SetCode(addr, []byte("1"))
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"not enough balance to cover tx cost",
|
||||||
|
tx,
|
||||||
|
func() {
|
||||||
|
// reset back to EOA
|
||||||
|
vmdb.SetCode(addr, nil)
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success new account",
|
||||||
|
tx,
|
||||||
|
func() {
|
||||||
|
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success existing account",
|
||||||
|
tx,
|
||||||
|
func() {
|
||||||
|
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||||
|
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||||
|
|
||||||
|
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
vmdb = suite.StateDB()
|
||||||
|
tc.malleate()
|
||||||
|
suite.Require().NoError(vmdb.Commit())
|
||||||
|
|
||||||
|
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx.WithIsCheckTx(tc.checkTx)), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestEthNonceVerificationDecorator() {
|
||||||
|
suite.SetupTest()
|
||||||
|
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthIncrementSenderSequenceMiddleware(suite.app.AccountKeeper))
|
||||||
|
addr := tests.GenerateAddress()
|
||||||
|
|
||||||
|
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
tx.From = addr.Hex()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
tx sdk.Tx
|
||||||
|
malleate func()
|
||||||
|
reCheckTx bool
|
||||||
|
expPass bool
|
||||||
|
}{
|
||||||
|
{"ReCheckTx", &invalidTx{}, func() {}, true, false},
|
||||||
|
{"invalid transaction type", &invalidTx{}, func() {}, false, false},
|
||||||
|
{"sender account not found", tx, func() {}, false, false},
|
||||||
|
{
|
||||||
|
"sender nonce missmatch",
|
||||||
|
tx,
|
||||||
|
func() {
|
||||||
|
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||||
|
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success",
|
||||||
|
tx,
|
||||||
|
func() {
|
||||||
|
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||||
|
suite.Require().NoError(acc.SetSequence(1))
|
||||||
|
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
tc.malleate()
|
||||||
|
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestEthGasConsumeDecorator() {
|
||||||
|
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthGasConsumeMiddleware(suite.app.EvmKeeper, config.DefaultMaxTxGasWanted))
|
||||||
|
|
||||||
|
addr := tests.GenerateAddress()
|
||||||
|
|
||||||
|
txGasLimit := uint64(1000)
|
||||||
|
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), txGasLimit, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
tx.From = addr.Hex()
|
||||||
|
|
||||||
|
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.From = addr.Hex()
|
||||||
|
|
||||||
|
var vmdb *statedb.StateDB
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
tx sdk.Tx
|
||||||
|
gasLimit uint64
|
||||||
|
malleate func()
|
||||||
|
expPass bool
|
||||||
|
expPanic bool
|
||||||
|
}{
|
||||||
|
{"invalid transaction type", &invalidTx{}, 0, func() {}, false, false},
|
||||||
|
{
|
||||||
|
"sender not found",
|
||||||
|
evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||||
|
0,
|
||||||
|
func() {},
|
||||||
|
false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"gas limit too low",
|
||||||
|
tx,
|
||||||
|
0,
|
||||||
|
func() {},
|
||||||
|
false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"not enough balance for fees",
|
||||||
|
tx2,
|
||||||
|
0,
|
||||||
|
func() {},
|
||||||
|
false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"not enough tx gas",
|
||||||
|
tx2,
|
||||||
|
0,
|
||||||
|
func() {
|
||||||
|
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||||
|
},
|
||||||
|
false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"not enough block gas",
|
||||||
|
tx2,
|
||||||
|
0,
|
||||||
|
func() {
|
||||||
|
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||||
|
|
||||||
|
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(1))
|
||||||
|
},
|
||||||
|
false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success",
|
||||||
|
tx2,
|
||||||
|
config.DefaultMaxTxGasWanted, // it's capped
|
||||||
|
func() {
|
||||||
|
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||||
|
|
||||||
|
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(10000000000000000000))
|
||||||
|
},
|
||||||
|
true, false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
vmdb = suite.StateDB()
|
||||||
|
tc.malleate()
|
||||||
|
suite.Require().NoError(vmdb.Commit())
|
||||||
|
|
||||||
|
if tc.expPanic {
|
||||||
|
suite.Require().Panics(func() {
|
||||||
|
_, _, _ = txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1))), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter())), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
|
||||||
|
// ctx, err := t.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter()), tc.tx, false, nextFn)
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
// suite.Require().Equal(tc.gasLimit, ctx.GasMeter().Limit())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestCanTransferDecorator() {
|
||||||
|
// dec := ante.NewCanTransferMiddleware(suite.app.EvmKeeper)
|
||||||
|
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewCanTransferMiddleware(suite.app.EvmKeeper))
|
||||||
|
|
||||||
|
addr, privKey := tests.NewAddrKey()
|
||||||
|
|
||||||
|
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, big.NewInt(100))
|
||||||
|
|
||||||
|
tx := evmtypes.NewTxContract(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
1,
|
||||||
|
big.NewInt(10),
|
||||||
|
1000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
ðtypes.AccessList{},
|
||||||
|
)
|
||||||
|
tx2 := evmtypes.NewTxContract(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
1,
|
||||||
|
big.NewInt(10),
|
||||||
|
1000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
ðtypes.AccessList{},
|
||||||
|
)
|
||||||
|
|
||||||
|
tx.From = addr.Hex()
|
||||||
|
|
||||||
|
err := tx.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
var vmdb *statedb.StateDB
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
tx sdk.Tx
|
||||||
|
malleate func()
|
||||||
|
expPass bool
|
||||||
|
}{
|
||||||
|
{"invalid transaction type", &invalidTx{}, func() {}, false},
|
||||||
|
{"AsMessage failed", tx2, func() {}, false},
|
||||||
|
{
|
||||||
|
"evm CanTransfer failed",
|
||||||
|
tx,
|
||||||
|
func() {
|
||||||
|
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||||
|
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success",
|
||||||
|
tx,
|
||||||
|
func() {
|
||||||
|
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||||
|
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||||
|
|
||||||
|
vmdb.AddBalance(addr, big.NewInt(1000000))
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
vmdb = suite.StateDB()
|
||||||
|
tc.malleate()
|
||||||
|
suite.Require().NoError(vmdb.Commit())
|
||||||
|
|
||||||
|
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx.WithIsCheckTx(true)), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestEthIncrementSenderSequenceDecorator() {
|
||||||
|
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthIncrementSenderSequenceMiddleware(suite.app.AccountKeeper))
|
||||||
|
|
||||||
|
addr, privKey := tests.NewAddrKey()
|
||||||
|
|
||||||
|
contract := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 0, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
contract.From = addr.Hex()
|
||||||
|
err := contract.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
to := tests.GenerateAddress()
|
||||||
|
tx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 0, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
tx.From = addr.Hex()
|
||||||
|
err = tx.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
tx2 := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
tx2.From = addr.Hex()
|
||||||
|
err = tx2.Sign(suite.ethSigner, tests.NewSigner(privKey))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
tx sdk.Tx
|
||||||
|
malleate func()
|
||||||
|
expPass bool
|
||||||
|
expPanic bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"invalid transaction type",
|
||||||
|
&invalidTx{},
|
||||||
|
func() {},
|
||||||
|
false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"no signers",
|
||||||
|
evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil),
|
||||||
|
func() {},
|
||||||
|
false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account not set to store",
|
||||||
|
tx,
|
||||||
|
func() {},
|
||||||
|
false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - create contract",
|
||||||
|
contract,
|
||||||
|
func() {
|
||||||
|
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes())
|
||||||
|
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||||
|
},
|
||||||
|
true, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - call",
|
||||||
|
tx2,
|
||||||
|
func() {},
|
||||||
|
true, false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
tc.malleate()
|
||||||
|
|
||||||
|
if tc.expPanic {
|
||||||
|
suite.Require().Panics(func() {
|
||||||
|
_, _, _ = txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// _, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
|
||||||
|
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
msg := tc.tx.(*evmtypes.MsgEthereumTx)
|
||||||
|
|
||||||
|
txData, err := evmtypes.UnpackTxData(msg.Data)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, addr)
|
||||||
|
suite.Require().Equal(txData.GetNonce()+1, nonce)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestEthSetupContextDecorator() {
|
||||||
|
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthSetUpContextMiddleware(suite.app.EvmKeeper))
|
||||||
|
|
||||||
|
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
tx sdk.Tx
|
||||||
|
expPass bool
|
||||||
|
}{
|
||||||
|
{"invalid transaction type - does not implement GasTx", &invalidTx{}, false},
|
||||||
|
{
|
||||||
|
"success - transaction implement GasTx",
|
||||||
|
tx,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -19,17 +19,17 @@ const (
|
|||||||
type MD struct {
|
type MD struct {
|
||||||
ethMiddleware tx.Handler
|
ethMiddleware tx.Handler
|
||||||
cosmosMiddleware tx.Handler
|
cosmosMiddleware tx.Handler
|
||||||
cosmoseip792 tx.Handler
|
cosmoseip712 tx.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = MD{}
|
var _ tx.Handler = MD{}
|
||||||
|
|
||||||
func NewMiddleware(indexEventsStr []string, options HandlerOptions) (tx.Handler, error) {
|
func NewMiddleware(options HandlerOptions) (tx.Handler, error) {
|
||||||
ethMiddleware, err := newEthAuthMiddleware(options)
|
ethMiddleware, err := newEthAuthMiddleware(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cosmoseip792, err := newCosmosAnteHandlerEip712(options)
|
cosmoseip712, err := newCosmosAnteHandlerEip712(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -40,7 +40,7 @@ func NewMiddleware(indexEventsStr []string, options HandlerOptions) (tx.Handler,
|
|||||||
return MD{
|
return MD{
|
||||||
ethMiddleware: ethMiddleware,
|
ethMiddleware: ethMiddleware,
|
||||||
cosmosMiddleware: cosmosMiddleware,
|
cosmosMiddleware: cosmosMiddleware,
|
||||||
cosmoseip792: cosmoseip792,
|
cosmoseip712: cosmoseip712,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ func (md MD) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestChe
|
|||||||
anteHandler = md.ethMiddleware
|
anteHandler = md.ethMiddleware
|
||||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||||
anteHandler = md.cosmoseip792
|
anteHandler = md.cosmoseip712
|
||||||
default:
|
default:
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrUnknownExtensionOptions,
|
sdkerrors.ErrUnknownExtensionOptions,
|
||||||
@ -93,7 +93,7 @@ func (md MD) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error)
|
|||||||
anteHandler = md.ethMiddleware
|
anteHandler = md.ethMiddleware
|
||||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||||
anteHandler = md.cosmoseip792
|
anteHandler = md.cosmoseip712
|
||||||
default:
|
default:
|
||||||
return tx.Response{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrUnknownExtensionOptions,
|
sdkerrors.ErrUnknownExtensionOptions,
|
||||||
@ -122,7 +122,7 @@ func (md MD) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error
|
|||||||
anteHandler = md.ethMiddleware
|
anteHandler = md.ethMiddleware
|
||||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||||
anteHandler = md.cosmoseip792
|
anteHandler = md.cosmoseip712
|
||||||
default:
|
default:
|
||||||
return tx.Response{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrUnknownExtensionOptions,
|
sdkerrors.ErrUnknownExtensionOptions,
|
||||||
|
691
app/middleware/middleware_test.go
Normal file
691
app/middleware/middleware_test.go
Normal file
@ -0,0 +1,691 @@
|
|||||||
|
package middleware_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/types/tx"
|
||||||
|
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
||||||
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
ethparams "github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/tharsis/ethermint/tests"
|
||||||
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestAnteHandler() {
|
||||||
|
suite.enableFeemarket = false
|
||||||
|
suite.SetupTest() // reset
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt(10000000000))
|
||||||
|
|
||||||
|
suite.app.FeeMarketKeeper.SetBaseFee(suite.ctx, big.NewInt(100))
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
txFn func() sdk.Tx
|
||||||
|
checkTx bool
|
||||||
|
reCheckTx bool
|
||||||
|
expPass bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"success - DeliverTx (contract)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
signedContractTx := evmtypes.NewTxContract(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
1,
|
||||||
|
big.NewInt(10),
|
||||||
|
100000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
signedContractTx.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
false, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - CheckTx (contract)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
signedContractTx := evmtypes.NewTxContract(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
2,
|
||||||
|
big.NewInt(10),
|
||||||
|
100000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
signedContractTx.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - ReCheckTx (contract)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
signedContractTx := evmtypes.NewTxContract(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
3,
|
||||||
|
big.NewInt(10),
|
||||||
|
100000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
signedContractTx.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
false, true, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - DeliverTx",
|
||||||
|
func() sdk.Tx {
|
||||||
|
signedTx := evmtypes.NewTx(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
4,
|
||||||
|
&to,
|
||||||
|
big.NewInt(10),
|
||||||
|
100000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
false, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - CheckTx",
|
||||||
|
func() sdk.Tx {
|
||||||
|
signedTx := evmtypes.NewTx(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
5,
|
||||||
|
&to,
|
||||||
|
big.NewInt(10),
|
||||||
|
100000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - ReCheckTx",
|
||||||
|
func() sdk.Tx {
|
||||||
|
signedTx := evmtypes.NewTx(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
6,
|
||||||
|
&to,
|
||||||
|
big.NewInt(10),
|
||||||
|
100000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
}, false, true, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - CheckTx (cosmos tx not signed)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
signedTx := evmtypes.NewTx(
|
||||||
|
suite.app.EvmKeeper.ChainID(),
|
||||||
|
7,
|
||||||
|
&to,
|
||||||
|
big.NewInt(10),
|
||||||
|
100000,
|
||||||
|
big.NewInt(150),
|
||||||
|
big.NewInt(200),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
}, false, true, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||||
|
// bigger than MaxGasWanted
|
||||||
|
txBuilder.SetGasLimit(uint64(1 << 63))
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, true, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||||
|
txBuilder.SetMemo(strings.Repeat("*", 257))
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, true, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false, true)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, true, false, false,
|
||||||
|
},
|
||||||
|
// Based on EVMBackend.SendTransaction, for cosmos tx, forcing null for some fields except ExtensionOptions, Fee, MsgEthereumTx
|
||||||
|
// should be part of consensus
|
||||||
|
{
|
||||||
|
"fail - DeliverTx (cosmos tx signed)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, true)
|
||||||
|
return tx
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fail - DeliverTx (cosmos tx with memo)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||||
|
txBuilder.SetMemo("memo for cosmos tx not allowed")
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fail - DeliverTx (cosmos tx with timeoutheight)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||||
|
txBuilder.SetTimeoutHeight(10)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fail - DeliverTx (invalid fee amount)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||||
|
|
||||||
|
txData, err := evmtypes.UnpackTxData(signedTx.Data)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
expFee := txData.Fee()
|
||||||
|
invalidFee := new(big.Int).Add(expFee, big.NewInt(1))
|
||||||
|
invalidFeeAmount := sdk.Coins{sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewIntFromBigInt(invalidFee))}
|
||||||
|
txBuilder.SetFeeAmount(invalidFeeAmount)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fail - DeliverTx (invalid fee gaslimit)",
|
||||||
|
func() sdk.Tx {
|
||||||
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
signedTx.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||||
|
|
||||||
|
expGasLimit := signedTx.GetGas()
|
||||||
|
invalidGasLimit := expGasLimit + 1
|
||||||
|
txBuilder.SetGasLimit(invalidGasLimit)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"success - DeliverTx EIP712 signed Cosmos Tx with MsgSend",
|
||||||
|
func() sdk.Tx {
|
||||||
|
from := acc.GetAddress()
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
|
||||||
|
gas := uint64(200000)
|
||||||
|
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()
|
||||||
|
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000))
|
||||||
|
amount := sdk.NewCoins(coinAmount)
|
||||||
|
gas := uint64(200000)
|
||||||
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgDelegate(from, privKey, "ethermint_9000-1", gas, amount)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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(200000)))
|
||||||
|
gas := uint64(200000)
|
||||||
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9002-1", gas, amount)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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(200000)))
|
||||||
|
gas := uint64(200000)
|
||||||
|
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))))
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fails - DeliverTx EIP712 signed Cosmos Tx with empty signature",
|
||||||
|
func() sdk.Tx {
|
||||||
|
from := acc.GetAddress()
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
|
||||||
|
gas := uint64(200000)
|
||||||
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
||||||
|
sigsV2 := signing.SignatureV2{}
|
||||||
|
txBuilder.SetSignatures(sigsV2)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid sequence",
|
||||||
|
func() sdk.Tx {
|
||||||
|
from := acc.GetAddress()
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
|
||||||
|
gas := uint64(200000)
|
||||||
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
||||||
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
sigsV2 := signing.SignatureV2{
|
||||||
|
PubKey: privKey.PubKey(),
|
||||||
|
Data: &signing.SingleSignatureData{
|
||||||
|
SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
|
||||||
|
},
|
||||||
|
Sequence: nonce - 1,
|
||||||
|
}
|
||||||
|
txBuilder.SetSignatures(sigsV2)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid signMode",
|
||||||
|
func() sdk.Tx {
|
||||||
|
from := acc.GetAddress()
|
||||||
|
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
|
||||||
|
gas := uint64(200000)
|
||||||
|
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
|
||||||
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
sigsV2 := signing.SignatureV2{
|
||||||
|
PubKey: privKey.PubKey(),
|
||||||
|
Data: &signing.SingleSignatureData{
|
||||||
|
SignMode: signing.SignMode_SIGN_MODE_UNSPECIFIED,
|
||||||
|
},
|
||||||
|
Sequence: nonce,
|
||||||
|
}
|
||||||
|
txBuilder.SetSignatures(sigsV2)
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
}, false, false, false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx)
|
||||||
|
|
||||||
|
// expConsumed := params.TxGasContractCreation + params.TxGas
|
||||||
|
// _, err := suite.anteHandler(suite.ctx, tc.txFn(), false)
|
||||||
|
_, _, err := suite.anteHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.txFn()}, tx.RequestCheckTx{})
|
||||||
|
// suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
|
||||||
|
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
// suite.Require().Equal(int(expConsumed), int(suite.ctx.GasMeter().GasConsumed()))
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||||
|
addr, privKey := tests.NewAddrKey()
|
||||||
|
to := tests.GenerateAddress()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
txFn func() sdk.Tx
|
||||||
|
enableLondonHF bool
|
||||||
|
checkTx bool
|
||||||
|
reCheckTx bool
|
||||||
|
expPass bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
false, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
false, true, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
false, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true, false, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
false, true, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
false, true, true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||||
|
// bigger than MaxGasWanted
|
||||||
|
txBuilder.SetGasLimit(uint64(1 << 63))
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
|
||||||
|
txBuilder.SetMemo(strings.Repeat("*", 257))
|
||||||
|
return txBuilder.GetTx()
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true, false, false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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.From = addr.Hex()
|
||||||
|
|
||||||
|
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
|
||||||
|
return tx
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false, false, false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
suite.enableFeemarket = true
|
||||||
|
suite.enableLondonHF = tc.enableLondonHF
|
||||||
|
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(tc.checkTx).WithIsReCheckTx(tc.reCheckTx)
|
||||||
|
suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt((ethparams.InitialBaseFee+10)*100000))
|
||||||
|
// _, err := suite.anteHandler(suite.ctx, tc.txFn(), false)
|
||||||
|
_, _, err := suite.anteHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.txFn()}, tx.RequestCheckTx{})
|
||||||
|
if tc.expPass {
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
} else {
|
||||||
|
suite.Require().Error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
suite.enableFeemarket = false
|
||||||
|
suite.enableLondonHF = true
|
||||||
|
}
|
46
app/middleware/sigs_test.go
Normal file
46
app/middleware/sigs_test.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package middleware_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/tharsis/ethermint/tests"
|
||||||
|
"github.com/tharsis/ethermint/x/evm/statedb"
|
||||||
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite MiddlewareTestSuite) TestSignatures() {
|
||||||
|
suite.enableFeemarket = false
|
||||||
|
suite.SetupTest() // reset
|
||||||
|
|
||||||
|
addr, privKey := tests.NewAddrKey()
|
||||||
|
to := tests.GenerateAddress()
|
||||||
|
|
||||||
|
acc := statedb.NewEmptyAccount()
|
||||||
|
acc.Nonce = 1
|
||||||
|
acc.Balance = big.NewInt(10000000000)
|
||||||
|
|
||||||
|
suite.app.EvmKeeper.SetAccount(suite.ctx, addr, *acc)
|
||||||
|
msgEthereumTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil, nil, nil)
|
||||||
|
msgEthereumTx.From = addr.Hex()
|
||||||
|
|
||||||
|
// CreateTestTx will sign the msgEthereumTx but not sign the cosmos tx since we have signCosmosTx as false
|
||||||
|
tx := suite.CreateTestTx(msgEthereumTx, privKey, 1, false)
|
||||||
|
sigs, err := tx.GetSignaturesV2()
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// signatures of cosmos tx should be empty
|
||||||
|
suite.Require().Equal(len(sigs), 0)
|
||||||
|
|
||||||
|
txData, err := evmtypes.UnpackTxData(msgEthereumTx.Data)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
msgV, msgR, msgS := txData.GetRawSignatureValues()
|
||||||
|
|
||||||
|
ethTx := msgEthereumTx.AsTransaction()
|
||||||
|
ethV, ethR, ethS := ethTx.RawSignatureValues()
|
||||||
|
|
||||||
|
// The signatures of MsgehtereumTx should be the same with the corresponding eth tx
|
||||||
|
suite.Require().Equal(msgV, ethV)
|
||||||
|
suite.Require().Equal(msgR, ethR)
|
||||||
|
suite.Require().Equal(msgS, ethS)
|
||||||
|
}
|
322
app/middleware/utils_test.go
Normal file
322
app/middleware/utils_test.go
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
package middleware_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
clientTx "github.com/cosmos/cosmos-sdk/client/tx"
|
||||||
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
|
||||||
|
types2 "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
|
types3 "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/spf13/cast"
|
||||||
|
ante "github.com/tharsis/ethermint/app/middleware"
|
||||||
|
"github.com/tharsis/ethermint/ethereum/eip712"
|
||||||
|
"github.com/tharsis/ethermint/server/config"
|
||||||
|
"github.com/tharsis/ethermint/types"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/simapp"
|
||||||
|
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"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"
|
||||||
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
|
|
||||||
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||||
|
"github.com/tharsis/ethermint/app"
|
||||||
|
"github.com/tharsis/ethermint/encoding"
|
||||||
|
"github.com/tharsis/ethermint/tests"
|
||||||
|
"github.com/tharsis/ethermint/x/evm/statedb"
|
||||||
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
|
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// customTxHandler is a test middleware that will run a custom function.
|
||||||
|
type customTxHandler struct {
|
||||||
|
fn func(context.Context, tx.Request) (tx.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ tx.Handler = customTxHandler{}
|
||||||
|
|
||||||
|
func (h customTxHandler) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
return h.fn(ctx, req)
|
||||||
|
}
|
||||||
|
func (h customTxHandler) CheckTx(ctx context.Context, req tx.Request, _ tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
|
res, err := h.fn(ctx, req)
|
||||||
|
return res, tx.ResponseCheckTx{}, err
|
||||||
|
}
|
||||||
|
func (h customTxHandler) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
return h.fn(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// noopTxHandler is a test middleware that returns an empty response.
|
||||||
|
var noopTxHandler = customTxHandler{func(_ context.Context, _ tx.Request) (tx.Response, error) {
|
||||||
|
return tx.Response{}, nil
|
||||||
|
}}
|
||||||
|
|
||||||
|
type MiddlewareTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
|
||||||
|
ctx sdk.Context
|
||||||
|
app *app.EthermintApp
|
||||||
|
clientCtx client.Context
|
||||||
|
anteHandler tx.Handler
|
||||||
|
ethSigner ethtypes.Signer
|
||||||
|
enableFeemarket bool
|
||||||
|
enableLondonHF bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MiddlewareTestSuite) StateDB() *statedb.StateDB {
|
||||||
|
return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes())))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MiddlewareTestSuite) SetupTest() {
|
||||||
|
checkTx := false
|
||||||
|
|
||||||
|
suite.app = app.Setup(suite.T(), checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
|
||||||
|
if suite.enableFeemarket {
|
||||||
|
// setup feemarketGenesis params
|
||||||
|
feemarketGenesis := feemarkettypes.DefaultGenesisState()
|
||||||
|
feemarketGenesis.Params.EnableHeight = 1
|
||||||
|
feemarketGenesis.Params.NoBaseFee = false
|
||||||
|
// Verify feeMarket genesis
|
||||||
|
err := feemarketGenesis.Validate()
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
genesis[feemarkettypes.ModuleName] = app.AppCodec().MustMarshalJSON(feemarketGenesis)
|
||||||
|
}
|
||||||
|
if !suite.enableLondonHF {
|
||||||
|
evmGenesis := evmtypes.DefaultGenesisState()
|
||||||
|
maxInt := sdk.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)
|
||||||
|
}
|
||||||
|
return genesis
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 2, ChainID: "ethermint_9000-1", Time: time.Now().UTC()})
|
||||||
|
suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(evmtypes.DefaultEVMDenom, sdk.OneInt())))
|
||||||
|
suite.ctx = suite.ctx.WithBlockGasMeter(sdk.NewGasMeter(1000000000000000000))
|
||||||
|
suite.app.EvmKeeper.WithChainID(suite.ctx)
|
||||||
|
|
||||||
|
infCtx := suite.ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||||
|
suite.app.AccountKeeper.SetParams(infCtx, authtypes.DefaultParams())
|
||||||
|
|
||||||
|
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
||||||
|
// We're using TestMsg amino encoding in some tests, so register it here.
|
||||||
|
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
|
||||||
|
|
||||||
|
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
|
||||||
|
maxGasWanted := cast.ToUint64(config.DefaultMaxTxGasWanted)
|
||||||
|
|
||||||
|
options := ante.HandlerOptions{
|
||||||
|
TxDecoder: suite.clientCtx.TxConfig.TxDecoder(),
|
||||||
|
AccountKeeper: suite.app.AccountKeeper,
|
||||||
|
BankKeeper: suite.app.BankKeeper,
|
||||||
|
EvmKeeper: suite.app.EvmKeeper,
|
||||||
|
FeegrantKeeper: suite.app.FeeGrantKeeper,
|
||||||
|
Codec: suite.app.AppCodec(),
|
||||||
|
Debug: suite.app.Trace(),
|
||||||
|
LegacyRouter: suite.app.LegacyRouter,
|
||||||
|
MsgServiceRouter: suite.app.MsgSvcRouter,
|
||||||
|
FeeMarketKeeper: suite.app.FeeMarketKeeper,
|
||||||
|
SignModeHandler: suite.clientCtx.TxConfig.SignModeHandler(),
|
||||||
|
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||||
|
MaxTxGasWanted: maxGasWanted,
|
||||||
|
}
|
||||||
|
|
||||||
|
suite.Require().NoError(options.Validate())
|
||||||
|
middleware, err := ante.NewMiddleware(options)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
suite.anteHandler = middleware
|
||||||
|
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMiddlewareTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, &MiddlewareTestSuite{
|
||||||
|
enableLondonHF: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTestTx is a helper function to create a tx given multiple inputs.
|
||||||
|
func (suite *MiddlewareTestSuite) CreateTestTx(
|
||||||
|
msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey, accNum uint64, signCosmosTx bool,
|
||||||
|
unsetExtensionOptions ...bool,
|
||||||
|
) authsigning.Tx {
|
||||||
|
return suite.CreateTestTxBuilder(msg, priv, accNum, signCosmosTx).GetTx()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateTestTxBuilder is a helper function to create a tx builder given multiple inputs.
|
||||||
|
func (suite *MiddlewareTestSuite) CreateTestTxBuilder(
|
||||||
|
msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey, accNum uint64, signCosmosTx bool,
|
||||||
|
unsetExtensionOptions ...bool,
|
||||||
|
) client.TxBuilder {
|
||||||
|
var option *codectypes.Any
|
||||||
|
var err error
|
||||||
|
if len(unsetExtensionOptions) == 0 {
|
||||||
|
option, err = codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
|
||||||
|
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
|
||||||
|
suite.Require().True(ok)
|
||||||
|
|
||||||
|
if len(unsetExtensionOptions) == 0 {
|
||||||
|
builder.SetExtensionOptions(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = msg.Sign(suite.ethSigner, tests.NewSigner(priv))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
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())))
|
||||||
|
builder.SetFeeAmount(fees)
|
||||||
|
builder.SetGasLimit(msg.GetGas())
|
||||||
|
|
||||||
|
if signCosmosTx {
|
||||||
|
// First round: we gather all the signer infos. We use the "set empty
|
||||||
|
// signature" hack to do that.
|
||||||
|
sigV2 := signing.SignatureV2{
|
||||||
|
PubKey: priv.PubKey(),
|
||||||
|
Data: &signing.SingleSignatureData{
|
||||||
|
SignMode: suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(),
|
||||||
|
Signature: nil,
|
||||||
|
},
|
||||||
|
Sequence: txData.GetNonce(),
|
||||||
|
}
|
||||||
|
|
||||||
|
sigsV2 := []signing.SignatureV2{sigV2}
|
||||||
|
|
||||||
|
err = txBuilder.SetSignatures(sigsV2...)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Second round: all signer infos are set, so each signer can sign.
|
||||||
|
|
||||||
|
signerData := authsigning.SignerData{
|
||||||
|
ChainID: suite.ctx.ChainID(),
|
||||||
|
AccountNumber: accNum,
|
||||||
|
Sequence: txData.GetNonce(),
|
||||||
|
}
|
||||||
|
sigV2, err = clientTx.SignWithPrivKey(
|
||||||
|
suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(), signerData,
|
||||||
|
txBuilder, priv, suite.clientCtx.TxConfig, txData.GetNonce(),
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
sigsV2 = []signing.SignatureV2{sigV2}
|
||||||
|
|
||||||
|
err = txBuilder.SetSignatures(sigsV2...)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return txBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MiddlewareTestSuite) 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))))
|
||||||
|
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MiddlewareTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
|
||||||
|
// Build MsgSend
|
||||||
|
valEthAddr := tests.GenerateAddress()
|
||||||
|
valAddr := sdk.ValAddress(valEthAddr.Bytes())
|
||||||
|
msgSend := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
|
||||||
|
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *MiddlewareTestSuite) CreateTestEIP712CosmosTxBuilder(
|
||||||
|
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msg sdk.Msg,
|
||||||
|
) client.TxBuilder {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, from)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
pc, err := types.ParseChainID(chainId)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
ethChainId := pc.Uint64()
|
||||||
|
|
||||||
|
// GenerateTypedData TypedData
|
||||||
|
var ethermintCodec codec.ProtoCodecMarshaler
|
||||||
|
fee := legacytx.NewStdFee(gas, gasAmount)
|
||||||
|
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
|
||||||
|
|
||||||
|
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "", nil)
|
||||||
|
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msg, data, &eip712.FeeDelegationOptions{
|
||||||
|
FeePayer: from,
|
||||||
|
})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
sigHash, err := eip712.ComputeTypedDataHash(typedData)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Sign typedData
|
||||||
|
keyringSigner := tests.NewSigner(priv)
|
||||||
|
signature, pubKey, err := keyringSigner.SignByAddress(from, sigHash)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
||||||
|
|
||||||
|
// Add ExtensionOptionsWeb3Tx extension
|
||||||
|
var option *codectypes.Any
|
||||||
|
option, err = codectypes.NewAnyWithValue(&types.ExtensionOptionsWeb3Tx{
|
||||||
|
FeePayer: from.String(),
|
||||||
|
TypedDataChainID: ethChainId,
|
||||||
|
FeePayerSig: signature,
|
||||||
|
})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.clientCtx.TxConfig.SignModeHandler()
|
||||||
|
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()
|
||||||
|
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
|
||||||
|
suite.Require().True(ok)
|
||||||
|
|
||||||
|
builder.SetExtensionOptions(option)
|
||||||
|
builder.SetFeeAmount(gasAmount)
|
||||||
|
builder.SetGasLimit(gas)
|
||||||
|
|
||||||
|
sigsV2 := signing.SignatureV2{
|
||||||
|
PubKey: pubKey,
|
||||||
|
Data: &signing.SingleSignatureData{
|
||||||
|
SignMode: signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON,
|
||||||
|
},
|
||||||
|
Sequence: nonce,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = builder.SetSignatures(sigsV2)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
err = builder.SetMsgs(msg)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ sdk.Tx = &invalidTx{}
|
||||||
|
|
||||||
|
type invalidTx struct{}
|
||||||
|
|
||||||
|
func (invalidTx) GetMsgs() []sdk.Msg { return []sdk.Msg{nil} }
|
||||||
|
func (invalidTx) ValidateBasic() error { return nil }
|
@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
"github.com/cosmos/cosmos-sdk/std"
|
"github.com/cosmos/cosmos-sdk/std"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
cryptocodec "github.com/tharsis/ethermint/crypto/codec"
|
cryptocodec "github.com/tharsis/ethermint/crypto/codec"
|
||||||
@ -19,6 +20,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
|||||||
|
|
||||||
// RegisterInterfaces registers Interfaces from types, crypto, and SDK std.
|
// RegisterInterfaces registers Interfaces from types, crypto, and SDK std.
|
||||||
func RegisterInterfaces(interfaceRegistry codectypes.InterfaceRegistry) {
|
func RegisterInterfaces(interfaceRegistry codectypes.InterfaceRegistry) {
|
||||||
|
sdk.RegisterInterfaces(interfaceRegistry)
|
||||||
std.RegisterInterfaces(interfaceRegistry)
|
std.RegisterInterfaces(interfaceRegistry)
|
||||||
cryptocodec.RegisterInterfaces(interfaceRegistry)
|
cryptocodec.RegisterInterfaces(interfaceRegistry)
|
||||||
ethermint.RegisterInterfaces(interfaceRegistry)
|
ethermint.RegisterInterfaces(interfaceRegistry)
|
||||||
|
@ -19,7 +19,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
|||||||
&EthAccount{},
|
&EthAccount{},
|
||||||
)
|
)
|
||||||
registry.RegisterInterface(
|
registry.RegisterInterface(
|
||||||
"ethermint.v1.ExtensionOptionsWeb3Tx",
|
"ethermint.types.v1.ExtensionOptionsWeb3Tx",
|
||||||
(*ExtensionOptionsWeb3TxI)(nil),
|
(*ExtensionOptionsWeb3TxI)(nil),
|
||||||
&ExtensionOptionsWeb3Tx{},
|
&ExtensionOptionsWeb3Tx{},
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user