diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index f00c8df..ea18b7c 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -79,10 +79,7 @@ func (suite *AnteTestSuite) SetupTest() { } // CreateTestTx is a helper function to create a tx given multiple inputs. -func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string) (authsign.Tx, error) { - defaultSignMode, err := authsign.APISignModeToInternal(suite.clientCtx.TxConfig.SignModeHandler().DefaultMode()) - suite.NoError(err) - +func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string, signMode signing.SignMode) (authsign.Tx, error) { // First round: we gather all the signer infos. We use the "set empty // signature" hack to do that. var sigsV2 []signing.SignatureV2 @@ -91,7 +88,7 @@ func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums [] sigV2 := signing.SignatureV2{ PubKey: priv.PubKey(), Data: &signing.SingleSignatureData{ - SignMode: defaultSignMode, + SignMode: signMode, Signature: nil, }, Sequence: accSeqs[i], @@ -99,7 +96,7 @@ func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums [] sigsV2 = append(sigsV2, sigV2) } - err = suite.txBuilder.SetSignatures(sigsV2...) + err := suite.txBuilder.SetSignatures(sigsV2...) if err != nil { return nil, err } @@ -115,7 +112,7 @@ func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums [] PubKey: priv.PubKey(), } sigV2, err := tx.SignWithPrivKey( - context.TODO(), defaultSignMode, signerData, + context.TODO(), signMode, signerData, suite.txBuilder, priv, suite.clientCtx.TxConfig, accSeqs[i]) if err != nil { return nil, err diff --git a/app/ante/fee_test.go b/app/ante/fee_test.go index 74cb4f7..4c50f51 100644 --- a/app/ante/fee_test.go +++ b/app/ante/fee_test.go @@ -6,6 +6,7 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" + authsign "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/initia-labs/minievm/app/ante" ) @@ -33,7 +34,9 @@ func (suite *AnteTestSuite) Test_NotSpendingGasForTxWithFeeDenom() { suite.txBuilder.SetGasLimit(gasLimit) privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0} - tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID()) + defaultSignMode, err := authsign.APISignModeToInternal(suite.app.TxConfig().SignModeHandler().DefaultMode()) + suite.NoError(err) + tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID(), defaultSignMode) suite.Require().NoError(err) gasMeter := storetypes.NewGasMeter(500000) diff --git a/app/ante/sigverify.go b/app/ante/sigverify.go index 00a083b..9122bc6 100644 --- a/app/ante/sigverify.go +++ b/app/ante/sigverify.go @@ -22,6 +22,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/initia-labs/initia/crypto/ethsecp256k1" + evmkeeper "github.com/initia-labs/minievm/x/evm/keeper" ) // SigVerificationDecorator verifies all signatures for a tx and return an error if any are invalid. Note, @@ -81,8 +82,17 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set") } + skipSequenceCheck := false + if simulate && len(sigs) == 1 { + if sigData, ok := sig.Data.(*signing.SingleSignatureData); ok { + if sigData.SignMode == evmkeeper.SignMode_SIGN_MODE_ETHEREUM { + skipSequenceCheck = true + } + } + } + // Check account sequence number. - if sig.Sequence != acc.GetSequence() { + if !skipSequenceCheck && sig.Sequence != acc.GetSequence() { return ctx, errorsmod.Wrapf( sdkerrors.ErrWrongSequence, "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, diff --git a/app/ante/sigverify_test.go b/app/ante/sigverify_test.go new file mode 100644 index 0000000..310c5cf --- /dev/null +++ b/app/ante/sigverify_test.go @@ -0,0 +1,56 @@ +package ante_test + +import ( + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + + "github.com/initia-labs/minievm/app/ante" + evmkeeper "github.com/initia-labs/minievm/x/evm/keeper" +) + +func (suite *AnteTestSuite) Test_SkipSequenceCheck() { + suite.SetupTest() // setup + suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() + + priv1, _, addr1 := testdata.KeyTestPubAddr() + acc1 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1) + acc1.SetPubKey(priv1.PubKey()) + suite.app.AccountKeeper.SetAccount(suite.ctx, acc1) + + suite.txBuilder.SetMsgs(testdata.NewTestMsg(addr1)) + suite.txBuilder.SetSignatures() + + sigV2 := signing.SignatureV2{ + PubKey: priv1.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: evmkeeper.SignMode_SIGN_MODE_ETHEREUM, + Signature: nil, + }, + // invalid sequence + Sequence: 100, + } + + err := suite.txBuilder.SetSignatures(sigV2) + suite.NoError(err) + + // 1. simulate should skip sequence check + sigVerifyAnte := ante.NewSigVerificationDecorator(suite.app.AccountKeeper, suite.app.EVMKeeper, suite.app.TxConfig().SignModeHandler()) + _, err = sigVerifyAnte.AnteHandle(suite.ctx, suite.txBuilder.GetTx(), true, func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil }) + suite.NoError(err) + + // 2. simulate should check sequence when it is not ethereum sign mode + sigV2.Data.(*signing.SingleSignatureData).SignMode = signing.SignMode_SIGN_MODE_DIRECT + err = suite.txBuilder.SetSignatures(sigV2) + suite.NoError(err) + _, err = sigVerifyAnte.AnteHandle(suite.ctx, suite.txBuilder.GetTx(), true, func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil }) + suite.ErrorIs(err, sdkerrors.ErrWrongSequence) + + // 3. non-simulate should check sequence + sigV2.Data.(*signing.SingleSignatureData).SignMode = evmkeeper.SignMode_SIGN_MODE_ETHEREUM + err = suite.txBuilder.SetSignatures(sigV2) + suite.NoError(err) + _, err = sigVerifyAnte.AnteHandle(suite.ctx, suite.txBuilder.GetTx(), false, func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { return ctx, nil }) + suite.ErrorIs(err, sdkerrors.ErrWrongSequence) +}