github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/ante/NonceVerificationDecorator.go (about)

     1  package ante
     2  
     3  import (
     4  	"github.com/ethereum/go-ethereum/common"
     5  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/baseapp"
     6  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     7  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
     9  	evmtypes "github.com/fibonacci-chain/fbc/x/evm/types"
    10  )
    11  
    12  // NonceVerificationDecorator checks that the account nonce from the transaction matches
    13  // the sender account sequence.
    14  type NonceVerificationDecorator struct {
    15  	ak auth.AccountKeeper
    16  }
    17  
    18  // NewNonceVerificationDecorator creates a new NonceVerificationDecorator
    19  func NewNonceVerificationDecorator(ak auth.AccountKeeper) NonceVerificationDecorator {
    20  	return NonceVerificationDecorator{
    21  		ak: ak,
    22  	}
    23  }
    24  
    25  // AnteHandle validates that the transaction nonce is valid (equivalent to the sender account’s
    26  // current nonce).
    27  func (nvd NonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
    28  	if simulate {
    29  		return next(ctx, tx, simulate)
    30  	}
    31  
    32  	pinAnte(ctx.AnteTracer(), "NonceVerificationDecorator")
    33  	msgEthTx, ok := tx.(*evmtypes.MsgEthereumTx)
    34  	if !ok {
    35  		return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
    36  	}
    37  
    38  	if ctx.From() != "" {
    39  		msgEthTx.SetFrom(ctx.From())
    40  	}
    41  	// sender address should be in the tx cache from the previous AnteHandle call
    42  	address := msgEthTx.AccountAddress()
    43  	if address.Empty() {
    44  		panic("sender address cannot be empty")
    45  	}
    46  
    47  	acc := nvd.ak.GetAccount(ctx, address)
    48  	if acc == nil {
    49  		return ctx, sdkerrors.Wrapf(
    50  			sdkerrors.ErrUnknownAddress,
    51  			"account %s (%s) is nil", common.BytesToAddress(address.Bytes()), address,
    52  		)
    53  	}
    54  
    55  	seq := acc.GetSequence()
    56  	// if multiple transactions are submitted in succession with increasing nonces,
    57  	// all will be rejected except the first, since the first needs to be included in a block
    58  	// before the sequence increments
    59  	if ctx.IsCheckTx() {
    60  		ctx.SetAccountNonce(seq)
    61  		// will be checkTx and RecheckTx mode
    62  		if ctx.IsReCheckTx() {
    63  			// recheckTx mode
    64  
    65  			// sequence must strictly increasing
    66  			if msgEthTx.Data.AccountNonce != seq {
    67  				return ctx, sdkerrors.Wrapf(
    68  					sdkerrors.ErrInvalidSequence,
    69  					"invalid nonce; got %d, expected %d", msgEthTx.Data.AccountNonce, seq,
    70  				)
    71  			}
    72  		} else {
    73  			if baseapp.IsMempoolEnablePendingPool() {
    74  				if msgEthTx.Data.AccountNonce < seq {
    75  					return ctx, sdkerrors.Wrapf(
    76  						sdkerrors.ErrInvalidSequence,
    77  						"invalid nonce; got %d, expected %d",
    78  						msgEthTx.Data.AccountNonce, seq,
    79  					)
    80  				}
    81  			} else {
    82  				// checkTx mode
    83  				checkTxModeNonce := seq
    84  
    85  				if !baseapp.IsMempoolEnableRecheck() {
    86  					// if is enable recheck, the sequence of checkState will increase after commit(), so we do not need
    87  					// to add pending txs len in the mempool.
    88  					// but, if disable recheck, we will not increase sequence of checkState (even in force recheck case, we
    89  					// will also reset checkState), so we will need to add pending txs len to get the right nonce
    90  					gPool := baseapp.GetGlobalMempool()
    91  					if gPool != nil {
    92  						addr := evmtypes.EthAddressStringer(common.BytesToAddress(msgEthTx.AccountAddress().Bytes())).String()
    93  						if pendingNonce, ok := gPool.GetPendingNonce(addr); ok {
    94  							checkTxModeNonce = pendingNonce + 1
    95  						}
    96  					}
    97  				}
    98  
    99  				if baseapp.IsMempoolEnableSort() {
   100  					if msgEthTx.Data.AccountNonce < seq || msgEthTx.Data.AccountNonce > checkTxModeNonce {
   101  						return ctx, sdkerrors.Wrapf(
   102  							sdkerrors.ErrInvalidSequence,
   103  							"invalid nonce; got %d, expected in the range of [%d, %d]",
   104  							msgEthTx.Data.AccountNonce, seq, checkTxModeNonce,
   105  						)
   106  					}
   107  				} else {
   108  					if msgEthTx.Data.AccountNonce != checkTxModeNonce {
   109  						return ctx, sdkerrors.Wrapf(
   110  							sdkerrors.ErrInvalidSequence,
   111  							"invalid nonce; got %d, expected %d",
   112  							msgEthTx.Data.AccountNonce, checkTxModeNonce,
   113  						)
   114  					}
   115  				}
   116  			}
   117  		}
   118  	} else {
   119  		// only deliverTx mode
   120  		if msgEthTx.Data.AccountNonce != seq {
   121  			return ctx, sdkerrors.Wrapf(
   122  				sdkerrors.ErrInvalidSequence,
   123  				"invalid nonce; got %d, expected %d", msgEthTx.Data.AccountNonce, seq,
   124  			)
   125  		}
   126  	}
   127  
   128  	return next(ctx, tx, simulate)
   129  }