forked from cerc-io/laconicd-deprecated
more fixes
This commit is contained in:
+82
-18
@@ -2,6 +2,9 @@ package ante
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
|
||||
log "github.com/xlab/suplog"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
@@ -14,7 +17,6 @@ import (
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -28,6 +30,8 @@ const (
|
||||
type AccountKeeper interface {
|
||||
authante.AccountKeeper
|
||||
NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
|
||||
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
|
||||
SetAccount(ctx sdk.Context, account authtypes.AccountI)
|
||||
}
|
||||
|
||||
// BankKeeper defines an expected keeper interface for the bank module's Keeper
|
||||
@@ -42,26 +46,73 @@ type BankKeeper interface {
|
||||
// transaction-level processing (e.g. fee payment, signature verification) before
|
||||
// being passed onto it's respective handler.
|
||||
func NewAnteHandler(
|
||||
ak AccountKeeper, bankKeeper BankKeeper, evmKeeper EVMKeeper, signModeHandler authsigning.SignModeHandler,
|
||||
ak AccountKeeper,
|
||||
bankKeeper BankKeeper,
|
||||
evmKeeper EVMKeeper,
|
||||
signModeHandler authsigning.SignModeHandler,
|
||||
) sdk.AnteHandler {
|
||||
return func(
|
||||
ctx sdk.Context, tx sdk.Tx, sim bool,
|
||||
) (newCtx sdk.Context, err error) {
|
||||
var anteHandler sdk.AnteHandler
|
||||
switch tx.(type) {
|
||||
case *evmtypes.MsgEthereumTx:
|
||||
anteHandler = sdk.ChainAnteDecorators(
|
||||
NewEthSetupContextDecorator(), // outermost AnteDecorator. EthSetUpContext must be called first
|
||||
authante.NewRejectExtensionOptionsDecorator(),
|
||||
NewEthMempoolFeeDecorator(evmKeeper),
|
||||
authante.NewValidateBasicDecorator(),
|
||||
NewEthSigVerificationDecorator(),
|
||||
NewAccountVerificationDecorator(ak, bankKeeper, evmKeeper),
|
||||
NewNonceVerificationDecorator(ak),
|
||||
NewEthGasConsumeDecorator(ak, bankKeeper, evmKeeper),
|
||||
NewIncrementSenderSequenceDecorator(ak), // innermost AnteDecorator.
|
||||
)
|
||||
|
||||
defer Recover(&err)
|
||||
|
||||
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
|
||||
if ok {
|
||||
opts := txWithExtensions.GetExtensionOptions()
|
||||
if len(opts) > 0 {
|
||||
switch typeURL := opts[0].GetTypeUrl(); typeURL {
|
||||
case "/injective.evm.v1beta1.ExtensionOptionsEthereumTx":
|
||||
// handle as *evmtypes.MsgEthereumTx
|
||||
|
||||
anteHandler = sdk.ChainAnteDecorators(
|
||||
NewEthSetupContextDecorator(), // outermost AnteDecorator. EthSetUpContext must be called first
|
||||
NewEthMempoolFeeDecorator(evmKeeper),
|
||||
NewEthValidateBasicDecorator(),
|
||||
authante.TxTimeoutHeightDecorator{},
|
||||
NewEthSigVerificationDecorator(),
|
||||
NewEthAccountSetupDecorator(ak),
|
||||
NewEthAccountVerificationDecorator(ak, bankKeeper, evmKeeper),
|
||||
NewEthNonceVerificationDecorator(ak),
|
||||
NewEthGasConsumeDecorator(ak, bankKeeper, evmKeeper),
|
||||
NewEthIncrementSenderSequenceDecorator(ak), // innermost AnteDecorator.
|
||||
)
|
||||
|
||||
case "/injective.evm.v1beta1.ExtensionOptionsWeb3Tx":
|
||||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
|
||||
|
||||
switch tx.(type) {
|
||||
case sdk.Tx:
|
||||
anteHandler = sdk.ChainAnteDecorators(
|
||||
authante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
|
||||
authante.NewMempoolFeeDecorator(),
|
||||
authante.NewValidateBasicDecorator(),
|
||||
authante.TxTimeoutHeightDecorator{},
|
||||
authante.NewValidateMemoDecorator(ak),
|
||||
authante.NewConsumeGasForTxSizeDecorator(ak),
|
||||
authante.NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators
|
||||
authante.NewValidateSigCountDecorator(ak),
|
||||
authante.NewDeductFeeDecorator(ak, bankKeeper),
|
||||
authante.NewSigGasConsumeDecorator(ak, DefaultSigVerificationGasConsumer),
|
||||
authante.NewIncrementSequenceDecorator(ak), // innermost AnteDecorator
|
||||
)
|
||||
default:
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||
}
|
||||
|
||||
default:
|
||||
log.WithField("type_url", typeURL).Errorln("rejecting tx with unsupported extension option")
|
||||
return ctx, sdkerrors.ErrUnknownExtensionOptions
|
||||
}
|
||||
|
||||
return anteHandler(ctx, tx, sim)
|
||||
}
|
||||
}
|
||||
|
||||
// handle as totally normal Cosmos SDK tx
|
||||
|
||||
switch tx.(type) {
|
||||
case sdk.Tx:
|
||||
anteHandler = sdk.ChainAnteDecorators(
|
||||
authante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
|
||||
@@ -71,7 +122,6 @@ func NewAnteHandler(
|
||||
authante.TxTimeoutHeightDecorator{},
|
||||
authante.NewValidateMemoDecorator(ak),
|
||||
authante.NewConsumeGasForTxSizeDecorator(ak),
|
||||
authante.NewRejectFeeGranterDecorator(),
|
||||
authante.NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators
|
||||
authante.NewValidateSigCountDecorator(ak),
|
||||
authante.NewDeductFeeDecorator(ak, bankKeeper),
|
||||
@@ -87,7 +137,20 @@ func NewAnteHandler(
|
||||
}
|
||||
}
|
||||
|
||||
var _ = DefaultSigVerificationGasConsumer
|
||||
func Recover(err *error) {
|
||||
if r := recover(); r != nil {
|
||||
*err = sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r)
|
||||
|
||||
if e, ok := r.(error); ok {
|
||||
log.WithError(e).Errorln("ante handler panicked with an error")
|
||||
log.Debugln(string(debug.Stack()))
|
||||
} else {
|
||||
log.Errorln(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var _ authante.SignatureVerificationGasConsumer = DefaultSigVerificationGasConsumer
|
||||
|
||||
// DefaultSigVerificationGasConsumer is the default implementation of SignatureVerificationGasConsumer. It consumes gas
|
||||
// for signature verification based upon the public key type. The cost is fetched from the given params and is matched
|
||||
@@ -105,7 +168,7 @@ func DefaultSigVerificationGasConsumer(
|
||||
meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1")
|
||||
return nil
|
||||
|
||||
// support for etherum ECDSA secp256k1 keys
|
||||
// support for ethereum ECDSA secp256k1 keys
|
||||
case *ethsecp256k1.PubKey:
|
||||
meter.ConsumeGas(secp256k1VerifyCost, "ante verify: eth_secp256k1")
|
||||
return nil
|
||||
@@ -120,6 +183,7 @@ func DefaultSigVerificationGasConsumer(
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
default:
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey)
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/cosmos/ethermint/app"
|
||||
@@ -62,8 +62,7 @@ func (suite *AnteTestSuite) TestValidEthTx() {
|
||||
requireValidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
// the legacytx.NewStdTx has been deprecated and It only works with Amino now
|
||||
func (suite *AnteTestSuite) TestInValidTx() {
|
||||
func (suite *AnteTestSuite) TestValidTx() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
@@ -84,13 +83,13 @@ func (suite *AnteTestSuite) TestInValidTx() {
|
||||
msg1 := newTestMsg(addr1, addr2)
|
||||
msgs := []sdk.Msg{msg1}
|
||||
|
||||
privKeys := []cryptotypes.PrivKey{priv1, priv2}
|
||||
privKeys := []tmcrypto.PrivKey{priv1, priv2}
|
||||
accNums := []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs := []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
tx := newTestSDKTx(suite.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
requireValidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestSDKInvalidSigs() {
|
||||
@@ -116,7 +115,7 @@ func (suite *AnteTestSuite) TestSDKInvalidSigs() {
|
||||
// require validation failure with no signers
|
||||
msgs := []sdk.Msg{msg1}
|
||||
|
||||
privKeys := []cryptotypes.PrivKey{}
|
||||
privKeys := []tmcrypto.PrivKey{}
|
||||
accNums := []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs := []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
@@ -126,7 +125,7 @@ func (suite *AnteTestSuite) TestSDKInvalidSigs() {
|
||||
// require validation failure with invalid number of signers
|
||||
msgs = []sdk.Msg{msg1}
|
||||
|
||||
privKeys = []cryptotypes.PrivKey{priv1}
|
||||
privKeys = []tmcrypto.PrivKey{priv1}
|
||||
accNums = []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs = []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
@@ -137,7 +136,7 @@ func (suite *AnteTestSuite) TestSDKInvalidSigs() {
|
||||
msg2 := newTestMsg(addr1, addr3)
|
||||
msgs = []sdk.Msg{msg1, msg2}
|
||||
|
||||
privKeys = []cryptotypes.PrivKey{priv1, priv2, priv3}
|
||||
privKeys = []tmcrypto.PrivKey{priv1, priv2, priv3}
|
||||
accNums = []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber(), 0}
|
||||
accSeqs = []uint64{acc1.GetSequence(), acc2.GetSequence(), 0}
|
||||
|
||||
@@ -158,7 +157,7 @@ func (suite *AnteTestSuite) TestSDKInvalidAcc() {
|
||||
fee := newTestStdFee()
|
||||
msg1 := newTestMsg(addr1)
|
||||
msgs := []sdk.Msg{msg1}
|
||||
privKeys := []cryptotypes.PrivKey{priv1}
|
||||
privKeys := []tmcrypto.PrivKey{priv1}
|
||||
|
||||
// require validation failure with invalid account number
|
||||
accNums := []uint64{1}
|
||||
|
||||
+159
-51
@@ -4,11 +4,14 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
log "github.com/xlab/suplog"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
|
||||
ethermint "github.com/cosmos/ethermint/types"
|
||||
sidechain "github.com/cosmos/ethermint/types"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -37,6 +40,8 @@ func NewEthSetupContextDecorator() EthSetupContextDecorator {
|
||||
// This is undone at the EthGasConsumeDecorator, where the context is set with the
|
||||
// ethereum tx GasLimit.
|
||||
func (escd EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
|
||||
// all transactions must implement GasTx
|
||||
gasTx, ok := tx.(authante.GasTx)
|
||||
if !ok {
|
||||
@@ -58,6 +63,7 @@ func (escd EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
|
||||
)
|
||||
err = sdkerrors.Wrap(sdkerrors.ErrOutOfGas, log)
|
||||
default:
|
||||
log.Errorln(r)
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
@@ -89,41 +95,77 @@ func (emfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
msgEthTx, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
msgEthTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type, not implements sdk.FeeTx: %T", tx)
|
||||
}
|
||||
|
||||
evmDenom := emfd.evmKeeper.GetParams(ctx).EvmDenom
|
||||
txFee := msgEthTx.GetFee().AmountOf(evmDenom).Int64()
|
||||
if txFee < 0 {
|
||||
return ctx, sdkerrors.Wrap(
|
||||
sdkerrors.ErrInsufficientFee,
|
||||
"negative fee not allowed",
|
||||
)
|
||||
}
|
||||
|
||||
// fee = gas price * gas limit
|
||||
fee := sdk.NewDecCoin(evmDenom, sdk.NewIntFromBigInt(msgEthTx.Fee()))
|
||||
// txFee = GP * GL
|
||||
fee := sdk.NewInt64DecCoin(evmDenom, txFee)
|
||||
|
||||
minGasPrices := ctx.MinGasPrices()
|
||||
minFees := minGasPrices.AmountOf(evmDenom).MulInt64(int64(msgEthTx.Data.GasLimit))
|
||||
|
||||
// check that fee provided is greater than the minimum defined by the validator node
|
||||
// NOTE: we only check if the evm denom tokens are present in min gas prices. It is up to the
|
||||
// check that fee provided is greater than the minimum
|
||||
// NOTE: we only check if injs are present in min gas prices. It is up to the
|
||||
// sender if they want to send additional fees in other denominations.
|
||||
var hasEnoughFees bool
|
||||
if fee.Amount.GTE(minFees) {
|
||||
if fee.Amount.GTE(minGasPrices.AmountOf(evmDenom)) {
|
||||
hasEnoughFees = true
|
||||
}
|
||||
|
||||
// reject transaction if minimum gas price is not zero and the transaction does not
|
||||
// reject transaction if minimum gas price is positive and the transaction does not
|
||||
// meet the minimum fee
|
||||
if !ctx.MinGasPrices().IsZero() && !hasEnoughFees {
|
||||
return ctx, sdkerrors.Wrap(
|
||||
sdkerrors.ErrInsufficientFee,
|
||||
fmt.Sprintf("insufficient fee, got: %q required: %q", fee, minFees),
|
||||
fmt.Sprintf("insufficient fee, got: %q required: %q", fee, ctx.MinGasPrices()),
|
||||
)
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthValidateBasicDecorator will call tx.ValidateBasic and return any non-nil error.
|
||||
// If ValidateBasic passes, decorator calls next AnteHandler in chain. Note,
|
||||
// EthValidateBasicDecorator decorator will not get executed on ReCheckTx since it
|
||||
// is not dependent on application state.
|
||||
type EthValidateBasicDecorator struct{}
|
||||
|
||||
func NewEthValidateBasicDecorator() EthValidateBasicDecorator {
|
||||
return EthValidateBasicDecorator{}
|
||||
}
|
||||
|
||||
func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
// no need to validate basic on recheck tx, call next antehandler
|
||||
if ctx.IsReCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
msgEthTx, ok := getTxMsg(tx).(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", getTxMsg(tx))
|
||||
}
|
||||
|
||||
if err := msgEthTx.ValidateBasic(); err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthSigVerificationDecorator validates an ethereum signature
|
||||
type EthSigVerificationDecorator struct{}
|
||||
type EthSigVerificationDecorator struct {
|
||||
interfaceRegistry codectypes.InterfaceRegistry
|
||||
}
|
||||
|
||||
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
|
||||
func NewEthSigVerificationDecorator() EthSigVerificationDecorator {
|
||||
@@ -132,39 +174,63 @@ func NewEthSigVerificationDecorator() EthSigVerificationDecorator {
|
||||
|
||||
// AnteHandle validates the signature and returns sender address
|
||||
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
msgEthTx, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
if simulate {
|
||||
// when simulating, no signatures required and the from address is explicitly set
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
msgEthTx, ok := getTxMsg(tx).(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", getTxMsg(tx))
|
||||
}
|
||||
|
||||
// parse the chainID from a string to a base-10 integer
|
||||
chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
|
||||
chainIDEpoch, err := sidechain.ParseChainID(ctx.ChainID())
|
||||
if err != nil {
|
||||
fmt.Println("chain id parsing failed")
|
||||
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
// validate sender/signature and cache the address
|
||||
_, err = msgEthTx.VerifySig(chainIDEpoch)
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "signature verification failed: %s", err.Error())
|
||||
// validate sender/signature
|
||||
_, eip155Err := msgEthTx.VerifySig(chainIDEpoch)
|
||||
if eip155Err != nil {
|
||||
_, homesteadErr := msgEthTx.VerifySigHomestead()
|
||||
if homesteadErr != nil {
|
||||
errMsg := fmt.Sprintf("signature verification failed for both EIP155 and Homestead signers: (%s, %s)",
|
||||
eip155Err.Error(), homesteadErr.Error())
|
||||
err := sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg)
|
||||
return ctx, err
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: when signature verification succeeds, a non-empty signer address can be
|
||||
// retrieved from the transaction on the next AnteDecorators.
|
||||
|
||||
return next(ctx, msgEthTx, simulate)
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// AccountVerificationDecorator validates an account balance checks
|
||||
type AccountVerificationDecorator struct {
|
||||
type noMessages struct{}
|
||||
|
||||
func getTxMsg(tx sdk.Tx) interface{} {
|
||||
msgs := tx.GetMsgs()
|
||||
if len(msgs) == 0 {
|
||||
return &noMessages{}
|
||||
}
|
||||
|
||||
return msgs[0]
|
||||
}
|
||||
|
||||
// EthAccountVerificationDecorator validates an account balance checks
|
||||
type EthAccountVerificationDecorator struct {
|
||||
ak AccountKeeper
|
||||
bankKeeper BankKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
// NewAccountVerificationDecorator creates a new AccountVerificationDecorator
|
||||
func NewAccountVerificationDecorator(ak AccountKeeper, bankKeeper BankKeeper, ek EVMKeeper) AccountVerificationDecorator {
|
||||
return AccountVerificationDecorator{
|
||||
// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator
|
||||
func NewEthAccountVerificationDecorator(ak AccountKeeper, bankKeeper BankKeeper, ek EVMKeeper) EthAccountVerificationDecorator {
|
||||
return EthAccountVerificationDecorator{
|
||||
ak: ak,
|
||||
bankKeeper: bankKeeper,
|
||||
evmKeeper: ek,
|
||||
@@ -172,20 +238,20 @@ func NewAccountVerificationDecorator(ak AccountKeeper, bankKeeper BankKeeper, ek
|
||||
}
|
||||
|
||||
// AnteHandle validates the signature and returns sender address
|
||||
func (avd AccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
if !ctx.IsCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
msgEthTx, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
msgEthTx, ok := getTxMsg(tx).(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", getTxMsg(tx))
|
||||
}
|
||||
|
||||
// sender address should be in the tx cache from the previous AnteHandle call
|
||||
address := msgEthTx.GetFrom()
|
||||
if address.Empty() {
|
||||
panic("sender address cannot be empty")
|
||||
log.Panicln("sender address cannot be empty")
|
||||
}
|
||||
|
||||
acc := avd.ak.GetAccount(ctx, address)
|
||||
@@ -216,31 +282,31 @@ func (avd AccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// NonceVerificationDecorator checks that the account nonce from the transaction matches
|
||||
// EthNonceVerificationDecorator checks that the account nonce from the transaction matches
|
||||
// the sender account sequence.
|
||||
type NonceVerificationDecorator struct {
|
||||
type EthNonceVerificationDecorator struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
// NewNonceVerificationDecorator creates a new NonceVerificationDecorator
|
||||
func NewNonceVerificationDecorator(ak AccountKeeper) NonceVerificationDecorator {
|
||||
return NonceVerificationDecorator{
|
||||
// NewEthNonceVerificationDecorator creates a new EthNonceVerificationDecorator
|
||||
func NewEthNonceVerificationDecorator(ak AccountKeeper) EthNonceVerificationDecorator {
|
||||
return EthNonceVerificationDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle validates that the transaction nonce is valid (equivalent to the sender account’s
|
||||
// current nonce).
|
||||
func (nvd NonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
msgEthTx, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
msgEthTx, ok := getTxMsg(tx).(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", getTxMsg(tx))
|
||||
}
|
||||
|
||||
// sender address should be in the tx cache from the previous AnteHandle call
|
||||
address := msgEthTx.GetFrom()
|
||||
if address.Empty() {
|
||||
panic("sender address cannot be empty")
|
||||
log.Panicln("sender address cannot be empty")
|
||||
}
|
||||
|
||||
acc := nvd.ak.GetAccount(ctx, address)
|
||||
@@ -290,15 +356,15 @@ func NewEthGasConsumeDecorator(ak AccountKeeper, bankKeeper BankKeeper, ek EVMKe
|
||||
// constant value of 21000 plus any cost inccured by additional bytes of data
|
||||
// supplied with the transaction.
|
||||
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
msgEthTx, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
msgEthTx, ok := getTxMsg(tx).(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", getTxMsg(tx))
|
||||
}
|
||||
|
||||
// sender address should be in the tx cache from the previous AnteHandle call
|
||||
address := msgEthTx.GetFrom()
|
||||
if address.Empty() {
|
||||
panic("sender address cannot be empty")
|
||||
log.Panicln("sender address cannot be empty")
|
||||
}
|
||||
|
||||
// fetch sender account from signature
|
||||
@@ -328,7 +394,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
// Charge sender for gas up to limit
|
||||
if gasLimit != 0 {
|
||||
// Cost calculates the fees paid to validators based on gas limit and price
|
||||
cost := new(big.Int).Mul(msgEthTx.Data.Price.BigInt(), new(big.Int).SetUint64(gasLimit))
|
||||
cost := new(big.Int).Mul(new(big.Int).SetBytes(msgEthTx.Data.Price), new(big.Int).SetUint64(gasLimit))
|
||||
|
||||
evmDenom := egcd.evmKeeper.GetParams(ctx).EvmDenom
|
||||
|
||||
@@ -347,40 +413,40 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
return next(newCtx, tx, simulate)
|
||||
}
|
||||
|
||||
// IncrementSenderSequenceDecorator increments the sequence of the signers. The
|
||||
// EthIncrementSenderSequenceDecorator increments the sequence of the signers. The
|
||||
// main difference with the SDK's IncrementSequenceDecorator is that the MsgEthereumTx
|
||||
// doesn't implement the SigVerifiableTx interface.
|
||||
//
|
||||
// CONTRACT: must be called after msg.VerifySig in order to cache the sender address.
|
||||
type IncrementSenderSequenceDecorator struct {
|
||||
type EthIncrementSenderSequenceDecorator struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
// NewIncrementSenderSequenceDecorator creates a new IncrementSenderSequenceDecorator.
|
||||
func NewIncrementSenderSequenceDecorator(ak AccountKeeper) IncrementSenderSequenceDecorator {
|
||||
return IncrementSenderSequenceDecorator{
|
||||
// NewEthIncrementSenderSequenceDecorator creates a new EthIncrementSenderSequenceDecorator.
|
||||
func NewEthIncrementSenderSequenceDecorator(ak AccountKeeper) EthIncrementSenderSequenceDecorator {
|
||||
return EthIncrementSenderSequenceDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle handles incrementing the sequence of the sender.
|
||||
func (issd IncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
// get and set account must be called with an infinite gas meter in order to prevent
|
||||
// additional gas from being deducted.
|
||||
gasMeter := ctx.GasMeter()
|
||||
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
|
||||
msgEthTx, ok := tx.(*evmtypes.MsgEthereumTx)
|
||||
msgEthTx, ok := getTxMsg(tx).(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
ctx = ctx.WithGasMeter(gasMeter)
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", getTxMsg(tx))
|
||||
}
|
||||
|
||||
// increment sequence of all signers
|
||||
for _, addr := range msgEthTx.GetSigners() {
|
||||
acc := issd.ak.GetAccount(ctx, addr)
|
||||
if err := acc.SetSequence(acc.GetSequence() + 1); err != nil {
|
||||
panic(err)
|
||||
log.WithError(err).Panicln("failed to set acc sequence")
|
||||
}
|
||||
issd.ak.SetAccount(ctx, acc)
|
||||
}
|
||||
@@ -389,3 +455,45 @@ func (issd IncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.
|
||||
ctx = ctx.WithGasMeter(gasMeter)
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthAccountSetupDecorator sets an account to state if it's not stored already. This only applies for MsgEthermint.
|
||||
type EthAccountSetupDecorator struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
// NewEthAccountSetupDecorator creates a new EthAccountSetupDecorator instance
|
||||
func NewEthAccountSetupDecorator(ak AccountKeeper) EthAccountSetupDecorator {
|
||||
return EthAccountSetupDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle sets an account for MsgEthereumTx (evm) if the sender is registered.
|
||||
func (asd EthAccountSetupDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
// get and set account must be called with an infinite gas meter in order to prevent
|
||||
// additional gas from being deducted.
|
||||
gasMeter := ctx.GasMeter()
|
||||
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
|
||||
msgEthTx, ok := getTxMsg(tx).(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
ctx = ctx.WithGasMeter(gasMeter)
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", getTxMsg(tx))
|
||||
}
|
||||
|
||||
setupAccount(asd.ak, ctx, msgEthTx.GetFrom())
|
||||
|
||||
// set the original gas meter
|
||||
ctx = ctx.WithGasMeter(gasMeter)
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
func setupAccount(ak AccountKeeper, ctx sdk.Context, addr sdk.AccAddress) {
|
||||
acc := ak.GetAccount(ctx, addr)
|
||||
if acc != nil {
|
||||
return
|
||||
}
|
||||
|
||||
acc = ak.NewAccountWithAddress(ctx, addr)
|
||||
ak.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
+20
-20
@@ -6,22 +6,22 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/simapp/params"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
"github.com/cosmos/ethermint/app"
|
||||
ante "github.com/cosmos/ethermint/app/ante"
|
||||
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
|
||||
ethermint "github.com/cosmos/ethermint/types"
|
||||
sidechain "github.com/cosmos/ethermint/types"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
)
|
||||
|
||||
@@ -39,11 +39,11 @@ func (suite *AnteTestSuite) SetupTest() {
|
||||
|
||||
suite.app = app.Setup(checkTx)
|
||||
|
||||
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 2, ChainID: "ethermint-3", Time: time.Now().UTC()})
|
||||
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 2, ChainID: "injective-3", Time: time.Now().UTC()})
|
||||
suite.app.AccountKeeper.SetParams(suite.ctx, authtypes.DefaultParams())
|
||||
suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams())
|
||||
|
||||
suite.encodingConfig = app.MakeEncodingConfig()
|
||||
suite.encodingConfig = simapp.MakeEncodingConfig()
|
||||
// We're using TestMsg amino encoding in some tests, so register it here.
|
||||
suite.encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
|
||||
|
||||
@@ -54,20 +54,20 @@ func TestAnteTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(AnteTestSuite))
|
||||
}
|
||||
|
||||
func newTestMsg(addrs ...sdk.AccAddress) *testdata.TestMsg {
|
||||
return testdata.NewTestMsg(addrs...)
|
||||
func newTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg {
|
||||
return sdk.NewTestMsg(addrs...)
|
||||
}
|
||||
|
||||
func newTestCoins() sdk.Coins {
|
||||
return sdk.NewCoins(ethermint.NewPhotonCoinInt64(500000000))
|
||||
return sdk.NewCoins(sidechain.NewPhotonCoinInt64(500000000))
|
||||
}
|
||||
|
||||
func newTestStdFee() legacytx.StdFee {
|
||||
return legacytx.NewStdFee(220000, sdk.NewCoins(ethermint.NewPhotonCoinInt64(150)))
|
||||
func newTestStdFee() auth.StdFee {
|
||||
return auth.NewStdFee(220000, sdk.NewCoins(sidechain.NewPhotonCoinInt64(150)))
|
||||
}
|
||||
|
||||
// GenerateAddress generates an Ethereum address.
|
||||
func newTestAddrKey() (sdk.AccAddress, cryptotypes.PrivKey) {
|
||||
func newTestAddrKey() (sdk.AccAddress, tmcrypto.PrivKey) {
|
||||
privkey, _ := ethsecp256k1.GenerateKey()
|
||||
addr := ethcrypto.PubkeyToAddress(privkey.ToECDSA().PublicKey)
|
||||
|
||||
@@ -75,30 +75,30 @@ func newTestAddrKey() (sdk.AccAddress, cryptotypes.PrivKey) {
|
||||
}
|
||||
|
||||
func newTestSDKTx(
|
||||
ctx sdk.Context, msgs []sdk.Msg, privs []cryptotypes.PrivKey,
|
||||
accNums []uint64, seqs []uint64, fee legacytx.StdFee,
|
||||
ctx sdk.Context, msgs []sdk.Msg, privs []tmcrypto.PrivKey,
|
||||
accNums []uint64, seqs []uint64, fee auth.StdFee,
|
||||
) sdk.Tx {
|
||||
|
||||
sigs := make([]legacytx.StdSignature, len(privs))
|
||||
sigs := make([]auth.StdSignature, len(privs))
|
||||
for i, priv := range privs {
|
||||
signBytes := legacytx.StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], 0, fee, msgs, "")
|
||||
signBytes := auth.StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, "")
|
||||
|
||||
sig, err := priv.Sign(signBytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sigs[i] = legacytx.StdSignature{
|
||||
sigs[i] = auth.StdSignature{
|
||||
PubKey: priv.PubKey(),
|
||||
Signature: sig,
|
||||
}
|
||||
}
|
||||
|
||||
return legacytx.NewStdTx(msgs, fee, sigs, "")
|
||||
return auth.NewStdTx(msgs, fee, sigs, "")
|
||||
}
|
||||
|
||||
func newTestEthTx(ctx sdk.Context, msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey) (sdk.Tx, error) {
|
||||
chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
|
||||
func newTestEthTx(ctx sdk.Context, msg *evmtypes.MsgEthereumTx, priv tmcrypto.PrivKey) (sdk.Tx, error) {
|
||||
chainIDEpoch, err := sidechain.ParseChainID(ctx.ChainID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user