github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/types/msg_evm.go (about)

     1  package types
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"math/big"
     9  	"sync"
    10  
    11  	ethcmn "github.com/ethereum/go-ethereum/common"
    12  	ethcrypto "github.com/ethereum/go-ethereum/crypto"
    13  	"github.com/ethereum/go-ethereum/rlp"
    14  	"github.com/fibonacci-chain/fbc/app/types"
    15  	ethermint "github.com/fibonacci-chain/fbc/app/types"
    16  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    17  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    18  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/ante"
    19  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    20  	"github.com/tendermint/go-amino"
    21  )
    22  
    23  var (
    24  	_ sdk.Msg    = (*MsgEthereumTx)(nil)
    25  	_ sdk.Tx     = (*MsgEthereumTx)(nil)
    26  	_ ante.FeeTx = (*MsgEthereumTx)(nil)
    27  )
    28  
    29  var big2 = big.NewInt(2)
    30  var big8 = big.NewInt(8)
    31  var DefaultDeployContractFnSignature = ethcmn.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")
    32  var DefaultSendCoinFnSignature = ethcmn.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000010")
    33  var emptyEthAddr = ethcmn.Address{}
    34  
    35  // message type and route constants
    36  const (
    37  	// TypeMsgEthereumTx defines the type string of an Ethereum tranasction
    38  	TypeMsgEthereumTx = "ethereum"
    39  )
    40  
    41  // MsgEthereumTx encapsulates an Ethereum transaction as an SDK message.
    42  type MsgEthereumTx struct {
    43  	Data TxData
    44  
    45  	sdk.BaseTx `json:"-" rlp:"-"`
    46  
    47  	addr ethcmn.Address
    48  }
    49  
    50  func (tx *MsgEthereumTx) GetType() sdk.TransactionType {
    51  	return sdk.EvmTxType
    52  }
    53  
    54  func (tx *MsgEthereumTx) SetFrom(addr string) {
    55  	tx.From = addr
    56  	tx.addr = ethcmn.HexToAddress(addr)
    57  }
    58  
    59  // GetFrom returns sender address of MsgEthereumTx if signature is valid, or returns "".
    60  func (tx *MsgEthereumTx) GetFrom() string {
    61  	from := tx.BaseTx.GetFrom()
    62  	if from != "" {
    63  		return from
    64  	}
    65  	from, _ = tmtypes.SignatureCache().Get(tx.TxHash())
    66  	if from != "" {
    67  		return from
    68  	}
    69  	// Verify the signature with chain-id in the tx, so it can be a tx from other chain with unexpected chain.
    70  	// Only use from addr for some safe usage and do not update the signature cache or the `From` field of the tx.
    71  	sender, err := tx.firstVerifySig(tx.ChainID())
    72  	if err != nil {
    73  		return ""
    74  	}
    75  	from = EthAddressToString(&sender)
    76  	return from
    77  }
    78  
    79  func (msg MsgEthereumTx) GetSender(ctx sdk.Context) string {
    80  	chainID, err := ethermint.ParseChainID(ctx.ChainID())
    81  	if err != nil {
    82  		return ""
    83  	}
    84  	err = msg.VerifySig(chainID, ctx.BlockHeight())
    85  	if err != nil {
    86  		return ""
    87  	}
    88  
    89  	return msg.BaseTx.GetFrom()
    90  }
    91  
    92  func (msg *MsgEthereumTx) GetNonce() uint64 {
    93  	return msg.Data.AccountNonce
    94  }
    95  
    96  func (msg *MsgEthereumTx) GetFee() sdk.Coins {
    97  	fee := make(sdk.Coins, 1)
    98  	feeInt := new(big.Int)
    99  	feeInt = msg.CalcFee(feeInt)
   100  	fee[0] = sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDecWithBigIntAndPrec(feeInt, sdk.Precision))
   101  	return fee
   102  }
   103  
   104  func (msg MsgEthereumTx) FeePayer(ctx sdk.Context) sdk.AccAddress {
   105  	chainID, err := ethermint.ParseChainID(ctx.ChainID())
   106  	if err != nil {
   107  		return nil
   108  	}
   109  	err = msg.VerifySig(chainID, ctx.BlockHeight())
   110  	if err != nil {
   111  		return nil
   112  	}
   113  
   114  	return msg.AccountAddress()
   115  }
   116  
   117  // NewMsgEthereumTx returns a reference to a new Ethereum transaction message.
   118  func NewMsgEthereumTx(
   119  	nonce uint64, to *ethcmn.Address, amount *big.Int,
   120  	gasLimit uint64, gasPrice *big.Int, payload []byte,
   121  ) *MsgEthereumTx {
   122  	return newMsgEthereumTx(nonce, to, amount, gasLimit, gasPrice, payload)
   123  }
   124  
   125  // NewMsgEthereumTxContract returns a reference to a new Ethereum transaction
   126  // message designated for contract creation.
   127  func NewMsgEthereumTxContract(
   128  	nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, payload []byte,
   129  ) *MsgEthereumTx {
   130  	return newMsgEthereumTx(nonce, nil, amount, gasLimit, gasPrice, payload)
   131  }
   132  
   133  func newMsgEthereumTx(
   134  	nonce uint64, to *ethcmn.Address, amount *big.Int,
   135  	gasLimit uint64, gasPrice *big.Int, payload []byte,
   136  ) *MsgEthereumTx {
   137  	if len(payload) > 0 {
   138  		payload = ethcmn.CopyBytes(payload)
   139  	}
   140  
   141  	txData := TxData{
   142  		AccountNonce: nonce,
   143  		Recipient:    to,
   144  		Payload:      payload,
   145  		GasLimit:     gasLimit,
   146  		Amount:       new(big.Int),
   147  		Price:        new(big.Int),
   148  		V:            new(big.Int),
   149  		R:            new(big.Int),
   150  		S:            new(big.Int),
   151  	}
   152  
   153  	if amount != nil {
   154  		txData.Amount.Set(amount)
   155  	}
   156  	if gasPrice != nil {
   157  		txData.Price.Set(gasPrice)
   158  	}
   159  
   160  	return &MsgEthereumTx{Data: txData}
   161  }
   162  
   163  func (msg *MsgEthereumTx) String() string {
   164  	return msg.Data.String()
   165  }
   166  
   167  // Route returns the route value of an MsgEthereumTx.
   168  func (msg *MsgEthereumTx) Route() string { return RouterKey }
   169  
   170  // Type returns the type value of an MsgEthereumTx.
   171  func (msg *MsgEthereumTx) Type() string { return TypeMsgEthereumTx }
   172  
   173  // ValidateBasic implements the sdk.Msg interface. It performs basic validation
   174  // checks of a Transaction. If returns an error if validation fails.
   175  func (msg *MsgEthereumTx) ValidateBasic() error {
   176  	if msg.Data.Price.Sign() <= 0 {
   177  		return sdkerrors.Wrapf(types.ErrInvalidValue, "gas price cannot be non positive %s", msg.Data.Price)
   178  	}
   179  
   180  	// Amount can be 0
   181  	if msg.Data.Amount.Sign() == -1 {
   182  		return sdkerrors.Wrapf(types.ErrInvalidValue, "amount cannot be negative %s", msg.Data.Amount)
   183  	}
   184  
   185  	return nil
   186  }
   187  
   188  // To returns the recipient address of the transaction. It returns nil if the
   189  // transaction is a contract creation.
   190  func (msg *MsgEthereumTx) To() *ethcmn.Address {
   191  	return msg.Data.Recipient
   192  }
   193  
   194  // GetSigners returns the expected signers for an Ethereum transaction message.
   195  // For such a message, there should exist only a single 'signer'.
   196  //
   197  // NOTE: This method panics if 'VerifySig' hasn't been called first.
   198  func (msg *MsgEthereumTx) GetSigners() []sdk.AccAddress {
   199  	addr := msg.AccountAddress()
   200  	if msg.BaseTx.From == "" || addr.Empty() {
   201  		panic("must use 'VerifySig' with a chain ID to get the from addr")
   202  	}
   203  	return []sdk.AccAddress{addr}
   204  }
   205  
   206  // GetSignBytes returns the Amino bytes of an Ethereum transaction message used
   207  // for signing.
   208  //
   209  // NOTE: This method cannot be used as a chain ID is needed to create valid bytes
   210  // to sign over. Use 'RLPSignBytes' instead.
   211  func (msg *MsgEthereumTx) GetSignBytes() []byte {
   212  	panic("must use 'RLPSignBytes' with a chain ID to get the valid bytes to sign")
   213  }
   214  
   215  type rlpHashData struct {
   216  	Params [9]interface{}
   217  	Hash   ethcmn.Hash
   218  
   219  	GasLimit uint64
   220  	Payload  []byte
   221  
   222  	ParamsSlice interface{}
   223  }
   224  
   225  var rlpHashDataPool = &sync.Pool{
   226  	New: func() interface{} {
   227  		data := &rlpHashData{}
   228  		data.ParamsSlice = data.Params[:]
   229  		return data
   230  	},
   231  }
   232  
   233  // RLPSignBytes returns the RLP hash of an Ethereum transaction message with a
   234  // given chainID used for signing.
   235  func (msg *MsgEthereumTx) RLPSignBytes(chainID *big.Int) (h ethcmn.Hash) {
   236  	rlpData := rlpHashDataPool.Get().(*rlpHashData)
   237  	rlpData.GasLimit = msg.Data.GasLimit
   238  	rlpData.Payload = msg.Data.Payload
   239  
   240  	rlpParams := &rlpData.Params
   241  	rlpParams[0] = msg.Data.AccountNonce
   242  	rlpParams[1] = msg.Data.Price
   243  	rlpParams[2] = &rlpData.GasLimit
   244  	rlpParams[3] = msg.Data.Recipient
   245  	rlpParams[4] = msg.Data.Amount
   246  	rlpParams[5] = &rlpData.Payload
   247  	rlpParams[6] = chainID
   248  	rlpParams[7] = uint(0)
   249  	rlpParams[8] = uint(0)
   250  	rlpHashTo(rlpData.ParamsSlice, &rlpData.Hash)
   251  	h = rlpData.Hash
   252  	rlpHashDataPool.Put(rlpData)
   253  	return
   254  }
   255  
   256  // Hash returns the hash to be signed by the sender.
   257  // It does not uniquely identify the transaction.
   258  func (msg *MsgEthereumTx) HomesteadSignHash() ethcmn.Hash {
   259  	return rlpHash([]interface{}{
   260  		msg.Data.AccountNonce,
   261  		msg.Data.Price,
   262  		msg.Data.GasLimit,
   263  		msg.Data.Recipient,
   264  		msg.Data.Amount,
   265  		msg.Data.Payload,
   266  	})
   267  }
   268  
   269  // EncodeRLP implements the rlp.Encoder interface.
   270  func (msg *MsgEthereumTx) EncodeRLP(w io.Writer) error {
   271  	return rlp.Encode(w, &msg.Data)
   272  }
   273  
   274  // DecodeRLP implements the rlp.Decoder interface.
   275  func (msg *MsgEthereumTx) DecodeRLP(s *rlp.Stream) error {
   276  	_, _, err := s.Kind()
   277  	if err != nil {
   278  		// return error if stream is too large
   279  		return err
   280  	}
   281  
   282  	if err := s.Decode(&msg.Data); err != nil {
   283  		return err
   284  	}
   285  
   286  	return nil
   287  }
   288  
   289  // Sign calculates a secp256k1 ECDSA signature and signs the transaction. It
   290  // takes a private key and chainID to sign an Ethereum transaction according to
   291  // EIP155 standard. It mutates the transaction as it populates the V, R, S
   292  // fields of the Transaction's Signature.
   293  func (msg *MsgEthereumTx) Sign(chainID *big.Int, priv *ecdsa.PrivateKey) error {
   294  	txHash := msg.RLPSignBytes(chainID)
   295  
   296  	sig, err := ethcrypto.Sign(txHash[:], priv)
   297  	if err != nil {
   298  		return err
   299  	}
   300  
   301  	if len(sig) != 65 {
   302  		return fmt.Errorf("wrong size for signature: got %d, want 65", len(sig))
   303  	}
   304  
   305  	r := new(big.Int).SetBytes(sig[:32])
   306  	s := new(big.Int).SetBytes(sig[32:64])
   307  
   308  	var v *big.Int
   309  
   310  	if chainID.Sign() == 0 {
   311  		v = new(big.Int).SetBytes([]byte{sig[64] + 27})
   312  	} else {
   313  		v = big.NewInt(int64(sig[64] + 35))
   314  		chainIDMul := new(big.Int).Mul(chainID, big.NewInt(2))
   315  
   316  		v.Add(v, chainIDMul)
   317  	}
   318  
   319  	msg.Data.V = v
   320  	msg.Data.R = r
   321  	msg.Data.S = s
   322  	return nil
   323  }
   324  
   325  var sigBigNumPool = &sync.Pool{
   326  	New: func() interface{} {
   327  		return new(big.Int)
   328  	},
   329  }
   330  
   331  func (msg *MsgEthereumTx) firstVerifySig(chainID *big.Int) (ethcmn.Address, error) {
   332  	var V *big.Int
   333  	var sigHash ethcmn.Hash
   334  	if isProtectedV(msg.Data.V) {
   335  		// do not allow recovery for transactions with an unprotected chainID
   336  		if chainID.Sign() == 0 {
   337  			return emptyEthAddr, errors.New("chainID cannot be zero")
   338  		}
   339  
   340  		bigNum := sigBigNumPool.Get().(*big.Int)
   341  		defer sigBigNumPool.Put(bigNum)
   342  		chainIDMul := bigNum.Mul(chainID, big2)
   343  		V = chainIDMul.Sub(msg.Data.V, chainIDMul)
   344  
   345  		// chainIDMul := new(big.Int).Mul(chainID, big2)
   346  		// V = new(big.Int).Sub(msg.Data.V, chainIDMul)
   347  		V.Sub(V, big8)
   348  
   349  		sigHash = msg.RLPSignBytes(chainID)
   350  	} else {
   351  		V = msg.Data.V
   352  
   353  		sigHash = msg.HomesteadSignHash()
   354  	}
   355  
   356  	sender, err := recoverEthSig(msg.Data.R, msg.Data.S, V, &sigHash)
   357  	if err != nil {
   358  		return emptyEthAddr, err
   359  	}
   360  	return sender, nil
   361  }
   362  
   363  // VerifySig attempts to verify a Transaction's signature for a given chainID.
   364  // A derived address is returned upon success or an error if recovery fails.
   365  func (msg *MsgEthereumTx) VerifySig(chainID *big.Int, height int64) error {
   366  	if !isProtectedV(msg.Data.V) &&
   367  		tmtypes.HigherThanMercury(height) &&
   368  		!tmtypes.HigherThanVenus5(height) {
   369  		return errors.New("deprecated support for homestead Signer")
   370  	}
   371  
   372  	if msg.BaseTx.GetFrom() != "" {
   373  		return nil
   374  	}
   375  	from, ok := tmtypes.SignatureCache().Get(msg.TxHash())
   376  	if ok {
   377  		msg.SetFrom(from)
   378  		return nil
   379  	}
   380  
   381  	if tmtypes.HigherThanJupiter(height) {
   382  		if types.IsJupiterBeforeMainNetChainId(chainID) {
   383  			chainID = big.NewInt(types.JupiterMainNetChainId)
   384  		} else if types.IsJupiterBeforeTestNetChainId(chainID) {
   385  			chainID = big.NewInt(types.JupiterTestNetChainId)
   386  		}
   387  	}
   388  
   389  	sender, err := msg.firstVerifySig(chainID)
   390  	if err != nil {
   391  		return err
   392  	}
   393  	from = EthAddressToString(&sender)
   394  	tmtypes.SignatureCache().Add(msg.TxHash(), from)
   395  	msg.BaseTx.From = from
   396  	msg.addr = sender
   397  	return nil
   398  }
   399  
   400  // Protected says whether the transaction is replay-protected.
   401  func (msg *MsgEthereumTx) Protected() bool {
   402  	return isProtectedV(msg.Data.V)
   403  }
   404  
   405  // codes from go-ethereum/core/types/transaction.go:122
   406  func isProtectedV(V *big.Int) bool {
   407  	if V.BitLen() <= 8 {
   408  		v := V.Uint64()
   409  		return v != 27 && v != 28
   410  	}
   411  	// anything not 27 or 28 is considered protected
   412  	return true
   413  }
   414  
   415  // GetGas implements the GasTx interface. It returns the GasLimit of the transaction.
   416  func (msg *MsgEthereumTx) GetGas() uint64 {
   417  	return msg.Data.GasLimit
   418  }
   419  
   420  // Fee returns gasprice * gaslimit.
   421  func (msg *MsgEthereumTx) Fee() *big.Int {
   422  	fee := new(big.Int)
   423  	fee.SetUint64(msg.Data.GasLimit)
   424  	fee.Mul(fee, msg.Data.Price)
   425  	return fee
   426  }
   427  
   428  // CalcFee set fee to gasprice * gaslimit and return fee
   429  func (msg *MsgEthereumTx) CalcFee(fee *big.Int) *big.Int {
   430  	fee.SetUint64(msg.Data.GasLimit)
   431  	fee.Mul(fee, msg.Data.Price)
   432  	return fee
   433  }
   434  
   435  // ChainID returns which chain id this transaction was signed for (if at all)
   436  func (msg *MsgEthereumTx) ChainID() *big.Int {
   437  	return deriveChainID(msg.Data.V)
   438  }
   439  
   440  // Cost returns amount + gasprice * gaslimit.
   441  func (msg *MsgEthereumTx) Cost() *big.Int {
   442  	total := msg.Fee()
   443  	total.Add(total, msg.Data.Amount)
   444  	return total
   445  }
   446  
   447  // CalcCostTo set total to amount + gasprice * gaslimit and return it
   448  func (msg *MsgEthereumTx) CalcCostTo(total *big.Int) *big.Int {
   449  	total = msg.CalcFee(total)
   450  	total.Add(total, msg.Data.Amount)
   451  	return total
   452  }
   453  
   454  // RawSignatureValues returns the V, R, S signature values of the transaction.
   455  // The return values should not be modified by the caller.
   456  func (msg *MsgEthereumTx) RawSignatureValues() (v, r, s *big.Int) {
   457  	return msg.Data.V, msg.Data.R, msg.Data.S
   458  }
   459  
   460  // From loads the ethereum sender address from the sigcache and returns an
   461  // sdk.AccAddress from its bytes
   462  func (msg *MsgEthereumTx) AccountAddress() sdk.AccAddress {
   463  	if msg.addr == emptyEthAddr {
   464  		return ethcmn.FromHex(msg.GetFrom())
   465  	} else {
   466  		return msg.addr[:]
   467  	}
   468  }
   469  
   470  func (msg *MsgEthereumTx) EthereumAddress() ethcmn.Address {
   471  	if msg.addr == emptyEthAddr {
   472  		return ethcmn.HexToAddress(msg.GetFrom())
   473  	} else {
   474  		return msg.addr
   475  	}
   476  }
   477  
   478  // deriveChainID derives the chain id from the given v parameter
   479  func deriveChainID(v *big.Int) *big.Int {
   480  	if v.BitLen() <= 64 {
   481  		v := v.Uint64()
   482  		if v == 27 || v == 28 {
   483  			return new(big.Int)
   484  		}
   485  		return new(big.Int).SetUint64((v - 35) / 2)
   486  	}
   487  	v = new(big.Int).Sub(v, big.NewInt(35))
   488  	return v.Div(v, big.NewInt(2))
   489  }
   490  
   491  func (msg *MsgEthereumTx) UnmarshalFromAmino(cdc *amino.Codec, data []byte) error {
   492  	var dataLen uint64 = 0
   493  	var subData []byte
   494  
   495  	for {
   496  		data = data[dataLen:]
   497  
   498  		if len(data) == 0 {
   499  			break
   500  		}
   501  
   502  		pos, pbType, err := amino.ParseProtoPosAndTypeMustOneByte(data[0])
   503  		if err != nil {
   504  			return err
   505  		}
   506  		data = data[1:]
   507  
   508  		if pbType == amino.Typ3_ByteLength {
   509  			var n int
   510  			dataLen, n, err = amino.DecodeUvarint(data)
   511  			if err != nil {
   512  				return err
   513  			}
   514  			data = data[n:]
   515  			if len(data) < int(dataLen) {
   516  				return fmt.Errorf("invalid tx data")
   517  			}
   518  			subData = data[:dataLen]
   519  		}
   520  
   521  		switch pos {
   522  		case 1:
   523  			if err := msg.Data.UnmarshalFromAmino(cdc, subData); err != nil {
   524  				return err
   525  			}
   526  		default:
   527  			return fmt.Errorf("unexpect feild num %d", pos)
   528  		}
   529  	}
   530  	return nil
   531  }