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
|
||||
appCodec codec.Codec
|
||||
interfaceRegistry types.InterfaceRegistry
|
||||
msgSvcRouter *authmiddleware.MsgServiceRouter
|
||||
legacyRouter sdk.Router
|
||||
MsgSvcRouter *authmiddleware.MsgServiceRouter
|
||||
LegacyRouter sdk.Router
|
||||
invCheckPeriod uint
|
||||
|
||||
// keys to access the substores
|
||||
@ -368,8 +368,8 @@ func NewEthermintApp(
|
||||
appCodec: appCodec,
|
||||
interfaceRegistry: interfaceRegistry,
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
legacyRouter: authmiddleware.NewLegacyRouter(),
|
||||
msgSvcRouter: authmiddleware.NewMsgServiceRouter(interfaceRegistry),
|
||||
LegacyRouter: authmiddleware.NewLegacyRouter(),
|
||||
MsgSvcRouter: authmiddleware.NewMsgServiceRouter(interfaceRegistry),
|
||||
keys: keys,
|
||||
tkeys: tkeys,
|
||||
memKeys: memKeys,
|
||||
@ -423,7 +423,7 @@ func NewEthermintApp(
|
||||
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))
|
||||
|
||||
@ -479,7 +479,7 @@ func NewEthermintApp(
|
||||
|
||||
govKeeper := govkeeper.NewKeeper(
|
||||
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(
|
||||
@ -644,8 +644,8 @@ func NewEthermintApp(
|
||||
)
|
||||
|
||||
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
||||
app.mm.RegisterRoutes(app.legacyRouter, app.QueryRouter(), encodingConfig.Amino)
|
||||
app.configurator = module.NewConfigurator(app.appCodec, app.msgSvcRouter, app.GRPCQueryRouter())
|
||||
app.mm.RegisterRoutes(app.LegacyRouter, app.QueryRouter(), encodingConfig.Amino)
|
||||
app.configurator = module.NewConfigurator(app.appCodec, app.MsgSvcRouter, app.GRPCQueryRouter())
|
||||
app.mm.RegisterServices(app.configurator)
|
||||
|
||||
// add test gRPC service for testing gRPC queries in isolation
|
||||
@ -685,8 +685,8 @@ func NewEthermintApp(
|
||||
options := middleware.HandlerOptions{
|
||||
Codec: app.appCodec,
|
||||
Debug: app.Trace(),
|
||||
LegacyRouter: app.legacyRouter,
|
||||
MsgServiceRouter: app.msgSvcRouter,
|
||||
LegacyRouter: app.LegacyRouter,
|
||||
MsgServiceRouter: app.MsgSvcRouter,
|
||||
AccountKeeper: app.AccountKeeper,
|
||||
BankKeeper: app.BankKeeper,
|
||||
EvmKeeper: app.EvmKeeper,
|
||||
@ -710,7 +710,9 @@ func (app *EthermintApp) setTxHandler(options middleware.HandlerOptions, txConfi
|
||||
indexEvents[e] = struct{}{}
|
||||
}
|
||||
|
||||
txHandler, err := middleware.NewMiddleware(indexEventsStr, options)
|
||||
options.IndexEvents = indexEvents
|
||||
|
||||
txHandler, err := middleware.NewMiddleware(options)
|
||||
if err != nil {
|
||||
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
|
||||
if ctx.IsReCheckTx() {
|
||||
return vbd.CheckTx(ctx, req, checkReq)
|
||||
return vbd.next.CheckTx(ctx, req, checkReq)
|
||||
}
|
||||
|
||||
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 {
|
||||
ethMiddleware tx.Handler
|
||||
cosmosMiddleware tx.Handler
|
||||
cosmoseip792 tx.Handler
|
||||
cosmoseip712 tx.Handler
|
||||
}
|
||||
|
||||
var _ tx.Handler = MD{}
|
||||
|
||||
func NewMiddleware(indexEventsStr []string, options HandlerOptions) (tx.Handler, error) {
|
||||
func NewMiddleware(options HandlerOptions) (tx.Handler, error) {
|
||||
ethMiddleware, err := newEthAuthMiddleware(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cosmoseip792, err := newCosmosAnteHandlerEip712(options)
|
||||
cosmoseip712, err := newCosmosAnteHandlerEip712(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -40,7 +40,7 @@ func NewMiddleware(indexEventsStr []string, options HandlerOptions) (tx.Handler,
|
||||
return MD{
|
||||
ethMiddleware: ethMiddleware,
|
||||
cosmosMiddleware: cosmosMiddleware,
|
||||
cosmoseip792: cosmoseip792,
|
||||
cosmoseip712: cosmoseip712,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ func (md MD) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestChe
|
||||
anteHandler = md.ethMiddleware
|
||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||
anteHandler = md.cosmoseip792
|
||||
anteHandler = md.cosmoseip712
|
||||
default:
|
||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrUnknownExtensionOptions,
|
||||
@ -93,7 +93,7 @@ func (md MD) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error)
|
||||
anteHandler = md.ethMiddleware
|
||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||
anteHandler = md.cosmoseip792
|
||||
anteHandler = md.cosmoseip712
|
||||
default:
|
||||
return tx.Response{}, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrUnknownExtensionOptions,
|
||||
@ -122,7 +122,7 @@ func (md MD) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error
|
||||
anteHandler = md.ethMiddleware
|
||||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
|
||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||
anteHandler = md.cosmoseip792
|
||||
anteHandler = md.cosmoseip712
|
||||
default:
|
||||
return tx.Response{}, sdkerrors.Wrapf(
|
||||
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"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/std"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
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.
|
||||
func RegisterInterfaces(interfaceRegistry codectypes.InterfaceRegistry) {
|
||||
sdk.RegisterInterfaces(interfaceRegistry)
|
||||
std.RegisterInterfaces(interfaceRegistry)
|
||||
cryptocodec.RegisterInterfaces(interfaceRegistry)
|
||||
ethermint.RegisterInterfaces(interfaceRegistry)
|
||||
|
@ -19,7 +19,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
&EthAccount{},
|
||||
)
|
||||
registry.RegisterInterface(
|
||||
"ethermint.v1.ExtensionOptionsWeb3Tx",
|
||||
"ethermint.types.v1.ExtensionOptionsWeb3Tx",
|
||||
(*ExtensionOptionsWeb3TxI)(nil),
|
||||
&ExtensionOptionsWeb3Tx{},
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user