Skip to content

Commit

Permalink
cherry-pick (evmos#689)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomas-nguy committed Oct 26, 2021
1 parent 476cbc4 commit fabf5d7
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 11 deletions.
2 changes: 1 addition & 1 deletion app/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func NewAnteHandler(
authante.NewMempoolFeeDecorator(),
authante.NewTxTimeoutHeightDecorator(),
authante.NewValidateMemoDecorator(ak),
NewEthValidateBasicDecorator(),
NewEthValidateBasicDecorator(evmKeeper),
NewEthSigVerificationDecorator(evmKeeper),
NewEthAccountVerificationDecorator(ak, bankKeeper, evmKeeper),
NewEthNonceVerificationDecorator(ak),
Expand Down
90 changes: 83 additions & 7 deletions app/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
signedContractTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 100000, big.NewInt(1), nil, nil)
signedContractTx.From = addr.Hex()

tx := suite.CreateTestTx(signedContractTx, privKey, 1, true)
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
return tx
},
false, false, true,
Expand All @@ -44,7 +44,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
signedContractTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 100000, big.NewInt(1), nil, nil)
signedContractTx.From = addr.Hex()

tx := suite.CreateTestTx(signedContractTx, privKey, 1, true)
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
return tx
},
true, false, true,
Expand All @@ -55,7 +55,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
signedContractTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 100000, big.NewInt(1), nil, nil)
signedContractTx.From = addr.Hex()

tx := suite.CreateTestTx(signedContractTx, privKey, 1, true)
tx := suite.CreateTestTx(signedContractTx, privKey, 1, false)
return tx
},
false, true, true,
Expand All @@ -66,7 +66,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 1, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil)
signedTx.From = addr.Hex()

tx := suite.CreateTestTx(signedTx, privKey, 1, true)
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
return tx
},
false, false, true,
Expand All @@ -77,7 +77,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 2, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil)
signedTx.From = addr.Hex()

tx := suite.CreateTestTx(signedTx, privKey, 1, true)
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
return tx
},
true, false, true,
Expand All @@ -88,7 +88,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 3, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil)
signedTx.From = addr.Hex()

tx := suite.CreateTestTx(signedTx, privKey, 1, true)
tx := suite.CreateTestTx(signedTx, privKey, 1, false)
return tx
}, false, true, true,
},
Expand Down Expand Up @@ -120,11 +120,87 @@ func (suite AnteTestSuite) TestAnteHandler() {
signedTx := evmtypes.NewTx(suite.app.EvmKeeper.ChainID(), 5, &to, big.NewInt(10), 100000, big.NewInt(1), nil, nil)
signedTx.From = addr.Hex()

txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, true)
txBuilder := suite.CreateTestTxBuilder(signedTx, privKey, 1, false)
txBuilder.SetMemo(strings.Repeat("*", 257))
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)
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)
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)
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)
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)
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,
},
}

for _, tc := range testCases {
Expand Down
97 changes: 94 additions & 3 deletions app/ante/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
tx "github.com/cosmos/cosmos-sdk/types/tx"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/palantir/stacktrace"

Expand Down Expand Up @@ -35,6 +36,10 @@ type EVMKeeper interface {
) (sdk.Coins, error)
}

type protoTxProvider interface {
GetProtoTx() *tx.Tx
}

// EthSigVerificationDecorator validates an ethereum signatures
type EthSigVerificationDecorator struct {
evmKeeper EVMKeeper
Expand Down Expand Up @@ -502,11 +507,15 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
}

// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
type EthValidateBasicDecorator struct{}
type EthValidateBasicDecorator struct {
evmKeeper EVMKeeper
}

// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
func NewEthValidateBasicDecorator() EthValidateBasicDecorator {
return EthValidateBasicDecorator{}
func NewEthValidateBasicDecorator(ek EVMKeeper) EthValidateBasicDecorator {
return EthValidateBasicDecorator{
evmKeeper: ek,
}
}

// AnteHandle handles basic validation of tx
Expand All @@ -522,6 +531,88 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
return ctx, stacktrace.Propagate(err, "tx basic validation failed")
}

// For eth type cosmos tx, some fields should be veified as zero values,
// since we will only verify the signature against the hash of the MsgEthereumTx.Data
if wrapperTx, ok := tx.(protoTxProvider); ok {
protoTx := wrapperTx.GetProtoTx()
body := protoTx.Body
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest,
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty"),
"invalid data in tx",
)
}

if len(body.ExtensionOptions) != 1 {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1"),
"invalid data in tx",
)
}

if len(protoTx.GetMsgs()) != 1 {
return ctx, stacktrace.Propagate(
sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx"),
"",
)
}
msg := protoTx.GetMsgs()[0]
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)),
"failed to cast transaction",
)
}
ethGasLimit := msgEthTx.GetGas()

txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, stacktrace.Propagate(err, "failed to unpack MsgEthereumTx Data")
}

params := vbd.evmKeeper.GetParams(ctx)
ethFeeAmount := sdk.Coins{sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(txData.Fee()))}

authInfo := protoTx.AuthInfo
if len(authInfo.SignerInfos) > 0 {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty"),
"invalid data in tx",
)
}

if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty"),
"invalid data in tx",
)
}

if !authInfo.Fee.Amount.IsEqual(ethFeeAmount) {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee Amount"),
"invalid data in tx",
)
}

if authInfo.Fee.GasLimit != ethGasLimit {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee GasLimit"),
"invalid data in tx",
)
}

sigs := protoTx.Signatures
if len(sigs) > 0 {
return ctx, stacktrace.Propagate(
sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty"),
"invalid data in tx",
)
}
}

return next(ctx, tx, simulate)
}

Expand Down

0 comments on commit fabf5d7

Please sign in to comment.