laconicd/x/evm/types/msg.go
Federico Kunze Küllmer 26c5eabb18
all: linter (#532)
* add additional linters

* fixes

* rm action
2021-09-05 11:03:06 +00:00

260 lines
6.9 KiB
Go

package types
import (
"fmt"
"math/big"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/tharsis/ethermint/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
var (
_ sdk.Msg = &MsgEthereumTx{}
_ sdk.Tx = &MsgEthereumTx{}
_ ante.GasTx = &MsgEthereumTx{}
_ codectypes.UnpackInterfacesMessage = MsgEthereumTx{}
)
// message type and route constants
const (
// TypeMsgEthereumTx defines the type string of an Ethereum transaction
TypeMsgEthereumTx = "ethereum_tx"
)
// NewTx returns a reference to a new Ethereum transaction message.
func NewTx(
chainID *big.Int, nonce uint64, to *common.Address, amount *big.Int,
gasLimit uint64, gasPrice *big.Int, input []byte, accesses *ethtypes.AccessList,
) *MsgEthereumTx {
return newMsgEthereumTx(chainID, nonce, to, amount, gasLimit, gasPrice, input, accesses)
}
// NewTxContract returns a reference to a new Ethereum transaction
// message designated for contract creation.
func NewTxContract(
chainID *big.Int, nonce uint64, amount *big.Int,
gasLimit uint64, gasPrice *big.Int, input []byte, accesses *ethtypes.AccessList,
) *MsgEthereumTx {
return newMsgEthereumTx(chainID, nonce, nil, amount, gasLimit, gasPrice, input, accesses)
}
func newMsgEthereumTx(
chainID *big.Int, nonce uint64, to *common.Address, amount *big.Int,
gasLimit uint64, gasPrice *big.Int, input []byte, accesses *ethtypes.AccessList,
) *MsgEthereumTx {
var (
cid, amt, gp *sdk.Int
toAddr string
txData TxData
)
if to != nil {
toAddr = to.Hex()
}
if amount != nil {
amountInt := sdk.NewIntFromBigInt(amount)
amt = &amountInt
}
if chainID != nil {
chainIDInt := sdk.NewIntFromBigInt(chainID)
cid = &chainIDInt
}
if gasPrice != nil {
gasPriceInt := sdk.NewIntFromBigInt(gasPrice)
gp = &gasPriceInt
}
if accesses == nil {
txData = &LegacyTx{
Nonce: nonce,
To: toAddr,
Amount: amt,
GasLimit: gasLimit,
GasPrice: gp,
Data: input,
}
} else {
txData = &AccessListTx{
ChainID: cid,
Nonce: nonce,
To: toAddr,
Amount: amt,
GasLimit: gasLimit,
GasPrice: gp,
Data: input,
Accesses: NewAccessList(accesses),
}
}
dataAny, err := PackTxData(txData)
if err != nil {
panic(err)
}
return &MsgEthereumTx{Data: dataAny}
}
// fromEthereumTx populates the message fields from the given ethereum transaction
func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) {
txData := NewTxDataFromTx(tx)
anyTxData, err := PackTxData(txData)
if err != nil {
panic(err)
}
msg.Data = anyTxData
msg.Size_ = float64(tx.Size())
msg.Hash = tx.Hash().Hex()
}
// Route returns the route value of an MsgEthereumTx.
func (msg MsgEthereumTx) Route() string { return RouterKey }
// Type returns the type value of an MsgEthereumTx.
func (msg MsgEthereumTx) Type() string { return TypeMsgEthereumTx }
// ValidateBasic implements the sdk.Msg interface. It performs basic validation
// checks of a Transaction. If returns an error if validation fails.
func (msg MsgEthereumTx) ValidateBasic() error {
if msg.From != "" {
if err := types.ValidateAddress(msg.From); err != nil {
return sdkerrors.Wrap(err, "invalid from address")
}
}
txData, err := UnpackTxData(msg.Data)
if err != nil {
return sdkerrors.Wrap(err, "failed to unpack tx data")
}
return txData.Validate()
}
// GetMsgs returns a single MsgEthereumTx as an sdk.Msg.
func (msg *MsgEthereumTx) GetMsgs() []sdk.Msg {
return []sdk.Msg{msg}
}
// GetSigners returns the expected signers for an Ethereum transaction message.
// For such a message, there should exist only a single 'signer'.
//
// NOTE: This method panics if 'Sign' hasn't been called first.
func (msg *MsgEthereumTx) GetSigners() []sdk.AccAddress {
data, err := UnpackTxData(msg.Data)
if err != nil {
panic(err)
}
sender, err := msg.GetSender(data.GetChainID())
if err != nil {
panic(err)
}
signer := sdk.AccAddress(sender.Bytes())
return []sdk.AccAddress{signer}
}
// GetSignBytes returns the Amino bytes of an Ethereum transaction message used
// for signing.
//
// NOTE: This method cannot be used as a chain ID is needed to create valid bytes
// to sign over. Use 'RLPSignBytes' instead.
func (msg MsgEthereumTx) GetSignBytes() []byte {
panic("must use 'RLPSignBytes' with a chain ID to get the valid bytes to sign")
}
// Sign calculates a secp256k1 ECDSA signature and signs the transaction. It
// takes a keyring signer and the chainID to sign an Ethereum transaction according to
// EIP155 standard.
// This method mutates the transaction as it populates the V, R, S
// fields of the Transaction's Signature.
// The function will fail if the sender address is not defined for the msg or if
// the sender is not registered on the keyring
func (msg *MsgEthereumTx) Sign(ethSigner ethtypes.Signer, keyringSigner keyring.Signer) error {
from := msg.GetFrom()
if from.Empty() {
return fmt.Errorf("sender address not defined for message")
}
tx := msg.AsTransaction()
txHash := ethSigner.Hash(tx)
sig, _, err := keyringSigner.SignByAddress(from, txHash.Bytes())
if err != nil {
return err
}
tx, err = tx.WithSignature(ethSigner, sig)
if err != nil {
return err
}
msg.FromEthereumTx(tx)
return nil
}
// GetGas implements the GasTx interface. It returns the GasLimit of the transaction.
func (msg MsgEthereumTx) GetGas() uint64 {
txData, err := UnpackTxData(msg.Data)
if err != nil {
return 0
}
return txData.GetGas()
}
// GetFrom loads the ethereum sender address from the sigcache and returns an
// sdk.AccAddress from its bytes
func (msg *MsgEthereumTx) GetFrom() sdk.AccAddress {
if msg.From == "" {
return nil
}
return common.HexToAddress(msg.From).Bytes()
}
// AsTransaction creates an Ethereum Transaction type from the msg fields
func (msg MsgEthereumTx) AsTransaction() *ethtypes.Transaction {
txData, err := UnpackTxData(msg.Data)
if err != nil {
return nil
}
return ethtypes.NewTx(txData.AsEthereumData())
}
// AsMessage creates an Ethereum core.Message from the msg fields
func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer) (core.Message, error) {
return msg.AsTransaction().AsMessage(signer)
}
// GetSender extracts the sender address from the signature values using the latest signer for the given chainID.
func (msg *MsgEthereumTx) GetSender(chainID *big.Int) (common.Address, error) {
signer := ethtypes.LatestSignerForChainID(chainID)
from, err := signer.Sender(msg.AsTransaction())
if err != nil {
return common.Address{}, err
}
msg.From = from.Hex()
return from, nil
}
// UnpackInterfaces implements UnpackInterfacesMesssage.UnpackInterfaces
func (msg MsgEthereumTx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
return unpacker.UnpackAny(msg.Data, new(TxData))
}