2021-11-02 11:20:19 +00:00
package types_test
2018-11-28 22:19:22 +00:00
import (
2021-11-02 11:20:19 +00:00
"fmt"
2018-11-28 22:19:22 +00:00
"math/big"
2021-11-02 11:20:19 +00:00
"reflect"
2018-11-28 22:19:22 +00:00
"testing"
2021-05-12 13:08:31 +00:00
"github.com/stretchr/testify/suite"
2020-04-23 15:49:25 +00:00
2021-11-02 11:20:19 +00:00
"github.com/cosmos/cosmos-sdk/client"
2021-05-12 13:08:31 +00:00
"github.com/cosmos/cosmos-sdk/crypto/keyring"
2020-04-23 15:49:25 +00:00
sdk "github.com/cosmos/cosmos-sdk/types"
2021-10-26 11:13:27 +00:00
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
2021-06-22 10:49:18 +00:00
"github.com/tharsis/ethermint/tests"
2021-04-17 10:00:07 +00:00
2021-07-05 16:39:08 +00:00
"github.com/ethereum/go-ethereum/common"
2021-10-26 11:13:27 +00:00
ethtypes "github.com/ethereum/go-ethereum/core/types"
2021-11-02 11:20:19 +00:00
"github.com/ethereum/go-ethereum/crypto"
"github.com/tharsis/ethermint/app"
"github.com/tharsis/ethermint/encoding"
"github.com/tharsis/ethermint/x/evm/types"
2018-11-28 22:19:22 +00:00
)
2021-06-29 15:08:07 +00:00
const invalidFromAddress = "0x0000"
2021-05-12 13:08:31 +00:00
type MsgsTestSuite struct {
suite . Suite
2020-04-23 15:49:25 +00:00
2021-05-12 13:08:31 +00:00
signer keyring . Signer
2021-09-03 18:06:36 +00:00
from common . Address
to common . Address
2021-05-12 13:08:31 +00:00
chainID * big . Int
2021-11-02 11:20:19 +00:00
clientCtx client . Context
2021-05-12 13:08:31 +00:00
}
func TestMsgsTestSuite ( t * testing . T ) {
suite . Run ( t , new ( MsgsTestSuite ) )
}
func ( suite * MsgsTestSuite ) SetupTest ( ) {
2021-09-07 17:29:24 +00:00
from , privFrom := tests . NewAddrKey ( )
2021-05-12 13:08:31 +00:00
suite . signer = tests . NewSigner ( privFrom )
2021-09-07 17:29:24 +00:00
suite . from = from
suite . to = tests . GenerateAddress ( )
2021-05-12 13:08:31 +00:00
suite . chainID = big . NewInt ( 1 )
2021-11-02 11:20:19 +00:00
encodingConfig := encoding . MakeConfig ( app . ModuleBasics )
suite . clientCtx = client . Context { } . WithTxConfig ( encodingConfig . TxConfig )
2021-05-12 13:08:31 +00:00
}
func ( suite * MsgsTestSuite ) TestMsgEthereumTx_Constructor ( ) {
2021-11-02 11:20:19 +00:00
msg := types . NewTx ( nil , 0 , & suite . to , nil , 100000 , nil , nil , nil , [ ] byte ( "test" ) , nil )
2021-05-12 13:08:31 +00:00
2021-07-05 16:39:08 +00:00
// suite.Require().Equal(msg.Data.To, suite.to.Hex())
2021-11-02 11:20:19 +00:00
suite . Require ( ) . Equal ( msg . Route ( ) , types . RouterKey )
suite . Require ( ) . Equal ( msg . Type ( ) , types . TypeMsgEthereumTx )
2021-07-05 16:39:08 +00:00
// suite.Require().NotNil(msg.To())
2021-05-12 13:08:31 +00:00
suite . Require ( ) . Equal ( msg . GetMsgs ( ) , [ ] sdk . Msg { msg } )
suite . Require ( ) . Panics ( func ( ) { msg . GetSigners ( ) } )
suite . Require ( ) . Panics ( func ( ) { msg . GetSignBytes ( ) } )
2020-04-23 15:49:25 +00:00
2021-11-02 11:20:19 +00:00
msg = types . NewTxContract ( nil , 0 , nil , 100000 , nil , nil , nil , [ ] byte ( "test" ) , nil )
2021-05-12 13:08:31 +00:00
suite . Require ( ) . NotNil ( msg )
2021-07-05 16:39:08 +00:00
// suite.Require().Empty(msg.Data.To)
// suite.Require().Nil(msg.To())
2018-11-28 22:19:22 +00:00
}
2021-11-02 11:20:19 +00:00
func ( suite * MsgsTestSuite ) TestMsgEthereumTx_BuildTx ( ) {
msg := types . NewTx ( nil , 0 , & suite . to , nil , 100000 , big . NewInt ( 1 ) , big . NewInt ( 1 ) , big . NewInt ( 0 ) , [ ] byte ( "test" ) , nil )
err := msg . ValidateBasic ( )
suite . Require ( ) . NoError ( err )
tx , err := msg . BuildTx ( suite . clientCtx . TxConfig . NewTxBuilder ( ) , "aphoton" )
suite . Require ( ) . NoError ( err )
suite . Require ( ) . Empty ( tx . GetMemo ( ) )
suite . Require ( ) . Empty ( tx . GetTimeoutHeight ( ) )
suite . Require ( ) . Equal ( uint64 ( 100000 ) , tx . GetGas ( ) )
suite . Require ( ) . Equal ( sdk . NewCoins ( sdk . NewCoin ( "aphoton" , sdk . NewInt ( 100000 ) ) ) , tx . GetFee ( ) )
}
2021-05-12 13:08:31 +00:00
func ( suite * MsgsTestSuite ) TestMsgEthereumTx_ValidateBasic ( ) {
2021-07-05 16:39:08 +00:00
hundredInt := sdk . NewInt ( 100 )
zeroInt := sdk . ZeroInt ( )
minusOneInt := sdk . NewInt ( - 1 )
2021-10-26 11:13:27 +00:00
exp_2_255 := sdk . NewIntFromBigInt ( new ( big . Int ) . Exp ( big . NewInt ( 2 ) , big . NewInt ( 255 ) , nil ) )
2021-07-05 16:39:08 +00:00
2018-11-28 22:19:22 +00:00
testCases := [ ] struct {
2020-04-23 15:49:25 +00:00
msg string
2021-06-29 15:08:07 +00:00
to string
2021-07-05 16:39:08 +00:00
amount * sdk . Int
gasPrice * sdk . Int
2021-06-11 13:38:51 +00:00
from string
2021-11-02 11:20:19 +00:00
accessList * ethtypes . AccessList
2021-07-05 16:39:08 +00:00
chainID * sdk . Int
2018-11-28 22:19:22 +00:00
expectPass bool
} {
2021-07-05 16:39:08 +00:00
{ msg : "pass with recipient - Legacy Tx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & hundredInt , expectPass : true } ,
2021-11-02 11:20:19 +00:00
{ msg : "pass with recipient - AccessList Tx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & zeroInt , accessList : & ethtypes . AccessList { } , chainID : & hundredInt , expectPass : true } ,
2021-07-05 16:39:08 +00:00
{ msg : "pass contract - Legacy Tx" , to : "" , amount : & hundredInt , gasPrice : & hundredInt , expectPass : true } ,
// {msg: "invalid recipient", to: invalidFromAddress, amount: &minusOneInt, gasPrice: &hundredInt, expectPass: false},
{ msg : "nil amount - Legacy Tx" , to : suite . to . Hex ( ) , amount : nil , gasPrice : & hundredInt , expectPass : true } ,
{ msg : "negative amount - Legacy Tx" , to : suite . to . Hex ( ) , amount : & minusOneInt , gasPrice : & hundredInt , expectPass : false } ,
{ msg : "nil gas price - Legacy Tx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : nil , expectPass : false } ,
{ msg : "negative gas price - Legacy Tx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & minusOneInt , expectPass : false } ,
{ msg : "zero gas price - Legacy Tx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & zeroInt , expectPass : true } ,
{ msg : "invalid from address - Legacy Tx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & zeroInt , from : invalidFromAddress , expectPass : false } ,
2021-10-26 11:13:27 +00:00
{ msg : "out of bound gas fee - Legacy Tx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & exp_2_255 , expectPass : false } ,
2021-11-02 11:20:19 +00:00
{ msg : "nil amount - AccessListTx" , to : suite . to . Hex ( ) , amount : nil , gasPrice : & hundredInt , accessList : & ethtypes . AccessList { } , chainID : & hundredInt , expectPass : true } ,
{ msg : "negative amount - AccessListTx" , to : suite . to . Hex ( ) , amount : & minusOneInt , gasPrice : & hundredInt , accessList : & ethtypes . AccessList { } , chainID : nil , expectPass : false } ,
{ msg : "nil gas price - AccessListTx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : nil , accessList : & ethtypes . AccessList { } , chainID : & hundredInt , expectPass : false } ,
{ msg : "negative gas price - AccessListTx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & minusOneInt , accessList : & ethtypes . AccessList { } , chainID : nil , expectPass : false } ,
{ msg : "zero gas price - AccessListTx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & zeroInt , accessList : & ethtypes . AccessList { } , chainID : & hundredInt , expectPass : true } ,
{ msg : "invalid from address - AccessListTx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & zeroInt , from : invalidFromAddress , accessList : & ethtypes . AccessList { } , chainID : & hundredInt , expectPass : false } ,
{ msg : "chain ID not set on AccessListTx" , to : suite . to . Hex ( ) , amount : & hundredInt , gasPrice : & zeroInt , accessList : & ethtypes . AccessList { } , chainID : nil , expectPass : false } ,
2018-11-28 22:19:22 +00:00
}
for i , tc := range testCases {
2021-07-05 16:39:08 +00:00
to := common . HexToAddress ( tc . from )
2021-06-29 15:08:07 +00:00
2021-07-05 16:39:08 +00:00
var chainID , amount , gasPrice * big . Int
if tc . chainID != nil {
chainID = tc . chainID . BigInt ( )
2021-06-29 15:08:07 +00:00
}
2021-07-05 16:39:08 +00:00
if tc . amount != nil {
amount = tc . amount . BigInt ( )
2021-06-29 15:08:07 +00:00
}
2021-07-05 16:39:08 +00:00
if tc . gasPrice != nil {
gasPrice = tc . gasPrice . BigInt ( )
2021-06-29 15:08:07 +00:00
}
2021-11-02 11:20:19 +00:00
tx := types . NewTx ( chainID , 1 , & to , amount , 1000 , gasPrice , nil , nil , nil , tc . accessList )
2021-07-05 16:39:08 +00:00
tx . From = tc . from
2021-06-29 15:08:07 +00:00
2021-07-05 16:39:08 +00:00
err := tx . ValidateBasic ( )
2018-11-28 22:19:22 +00:00
if tc . expectPass {
2021-07-05 16:39:08 +00:00
suite . Require ( ) . NoError ( err , "valid test %d failed: %s, %v" , i , tc . msg )
2018-11-28 22:19:22 +00:00
} else {
2021-07-05 16:39:08 +00:00
suite . Require ( ) . Error ( err , "invalid test %d passed: %s, %v" , i , tc . msg )
2018-11-28 22:19:22 +00:00
}
}
}
2021-05-12 13:08:31 +00:00
func ( suite * MsgsTestSuite ) TestMsgEthereumTx_Sign ( ) {
testCases := [ ] struct {
msg string
2021-11-02 11:20:19 +00:00
tx * types . MsgEthereumTx
ethSigner ethtypes . Signer
malleate func ( tx * types . MsgEthereumTx )
2021-05-12 13:08:31 +00:00
expectPass bool
} {
{
2021-06-01 17:14:33 +00:00
"pass - EIP2930 signer" ,
2021-11-02 11:20:19 +00:00
types . NewTx ( suite . chainID , 0 , & suite . to , nil , 100000 , nil , nil , nil , [ ] byte ( "test" ) , & ethtypes . AccessList { } ) ,
ethtypes . NewEIP2930Signer ( suite . chainID ) ,
func ( tx * types . MsgEthereumTx ) { tx . From = suite . from . Hex ( ) } ,
2021-05-12 13:08:31 +00:00
true ,
} ,
2021-06-01 17:14:33 +00:00
{
2021-06-11 13:38:51 +00:00
"pass - EIP155 signer" ,
2021-11-02 11:20:19 +00:00
types . NewTx ( suite . chainID , 0 , & suite . to , nil , 100000 , nil , nil , nil , [ ] byte ( "test" ) , nil ) ,
ethtypes . NewEIP155Signer ( suite . chainID ) ,
func ( tx * types . MsgEthereumTx ) { tx . From = suite . from . Hex ( ) } ,
2021-06-11 13:38:51 +00:00
true ,
2021-06-01 17:14:33 +00:00
} ,
{
2021-06-11 13:38:51 +00:00
"pass - Homestead signer" ,
2021-11-02 11:20:19 +00:00
types . NewTx ( suite . chainID , 0 , & suite . to , nil , 100000 , nil , nil , nil , [ ] byte ( "test" ) , nil ) ,
ethtypes . HomesteadSigner { } ,
func ( tx * types . MsgEthereumTx ) { tx . From = suite . from . Hex ( ) } ,
2021-06-11 13:38:51 +00:00
true ,
2021-06-01 17:14:33 +00:00
} ,
{
2021-06-11 13:38:51 +00:00
"pass - Frontier signer" ,
2021-11-02 11:20:19 +00:00
types . NewTx ( suite . chainID , 0 , & suite . to , nil , 100000 , nil , nil , nil , [ ] byte ( "test" ) , nil ) ,
ethtypes . FrontierSigner { } ,
func ( tx * types . MsgEthereumTx ) { tx . From = suite . from . Hex ( ) } ,
2021-06-11 13:38:51 +00:00
true ,
2021-06-01 17:14:33 +00:00
} ,
2021-05-12 13:08:31 +00:00
{
"no from address " ,
2021-11-02 11:20:19 +00:00
types . NewTx ( suite . chainID , 0 , & suite . to , nil , 100000 , nil , nil , nil , [ ] byte ( "test" ) , & ethtypes . AccessList { } ) ,
ethtypes . NewEIP2930Signer ( suite . chainID ) ,
func ( tx * types . MsgEthereumTx ) { tx . From = "" } ,
2021-05-12 13:08:31 +00:00
false ,
} ,
{
"from address ≠ signer address" ,
2021-11-02 11:20:19 +00:00
types . NewTx ( suite . chainID , 0 , & suite . to , nil , 100000 , nil , nil , nil , [ ] byte ( "test" ) , & ethtypes . AccessList { } ) ,
ethtypes . NewEIP2930Signer ( suite . chainID ) ,
func ( tx * types . MsgEthereumTx ) { tx . From = suite . to . Hex ( ) } ,
2021-05-12 13:08:31 +00:00
false ,
} ,
}
for i , tc := range testCases {
2021-06-11 13:38:51 +00:00
tc . malleate ( tc . tx )
2021-06-01 17:14:33 +00:00
2021-06-11 13:38:51 +00:00
err := tc . tx . Sign ( tc . ethSigner , suite . signer )
2021-05-12 13:08:31 +00:00
if tc . expectPass {
suite . Require ( ) . NoError ( err , "valid test %d failed: %s" , i , tc . msg )
2021-07-02 09:34:15 +00:00
sender , err := tc . tx . GetSender ( suite . chainID )
2021-05-12 13:08:31 +00:00
suite . Require ( ) . NoError ( err , tc . msg )
2021-06-11 13:38:51 +00:00
suite . Require ( ) . Equal ( tc . tx . From , sender . Hex ( ) , tc . msg )
2021-05-12 13:08:31 +00:00
} else {
suite . Require ( ) . Error ( err , "invalid test %d passed: %s" , i , tc . msg )
}
}
}
2021-10-26 11:13:27 +00:00
func ( suite * MsgsTestSuite ) TestFromEthereumTx ( ) {
privkey , _ := ethsecp256k1 . GenerateKey ( )
ethPriv , err := privkey . ToECDSA ( )
suite . Require ( ) . NoError ( err )
// 10^80 is more than 256 bits
exp_10_80 := new ( big . Int ) . Mul ( big . NewInt ( 1 ) , new ( big . Int ) . Exp ( big . NewInt ( 10 ) , big . NewInt ( 80 ) , nil ) )
testCases := [ ] struct {
msg string
expectPass bool
buildTx func ( ) * ethtypes . Transaction
} {
{ "success, normal tx" , true , func ( ) * ethtypes . Transaction {
tx := ethtypes . NewTransaction (
0 ,
common . BigToAddress ( big . NewInt ( 1 ) ) ,
big . NewInt ( 10 ) ,
21000 , big . NewInt ( 0 ) ,
nil ,
)
2021-11-02 11:20:19 +00:00
tx , err := ethtypes . SignTx ( tx , ethtypes . NewEIP2930Signer ( suite . chainID ) , ethPriv )
2021-10-26 11:13:27 +00:00
suite . Require ( ) . NoError ( err )
return tx
} } ,
{ "fail, value bigger than 256bits" , false , func ( ) * ethtypes . Transaction {
tx := ethtypes . NewTransaction (
0 ,
common . BigToAddress ( big . NewInt ( 1 ) ) ,
exp_10_80 ,
21000 , big . NewInt ( 0 ) ,
nil ,
)
2021-11-02 11:20:19 +00:00
tx , err := ethtypes . SignTx ( tx , ethtypes . NewEIP2930Signer ( suite . chainID ) , ethPriv )
2021-10-26 11:13:27 +00:00
suite . Require ( ) . NoError ( err )
return tx
} } ,
{ "fail, gas price bigger than 256bits" , false , func ( ) * ethtypes . Transaction {
tx := ethtypes . NewTransaction (
0 ,
common . BigToAddress ( big . NewInt ( 1 ) ) ,
big . NewInt ( 10 ) ,
21000 , exp_10_80 ,
nil ,
)
2021-11-02 11:20:19 +00:00
tx , err := ethtypes . SignTx ( tx , ethtypes . NewEIP2930Signer ( suite . chainID ) , ethPriv )
2021-10-26 11:13:27 +00:00
suite . Require ( ) . NoError ( err )
return tx
} } ,
}
for _ , tc := range testCases {
ethTx := tc . buildTx ( )
2021-11-02 11:20:19 +00:00
tx := & types . MsgEthereumTx { }
2021-10-26 11:13:27 +00:00
err := tx . FromEthereumTx ( ethTx )
if tc . expectPass {
suite . Require ( ) . NoError ( err )
// round-trip test
2021-11-02 11:20:19 +00:00
suite . Require ( ) . NoError ( assertEqual ( tx . AsTransaction ( ) , ethTx ) )
2021-10-26 11:13:27 +00:00
} else {
suite . Require ( ) . Error ( err )
}
}
}
2021-11-02 11:20:19 +00:00
// TestTransactionCoding tests serializing/de-serializing to/from rlp and JSON.
// adapted from go-ethereum
func ( suite * MsgsTestSuite ) TestTransactionCoding ( ) {
key , err := crypto . GenerateKey ( )
if err != nil {
suite . T ( ) . Fatalf ( "could not generate key: %v" , err )
}
var (
signer = ethtypes . NewEIP2930Signer ( common . Big1 )
addr = common . HexToAddress ( "0x0000000000000000000000000000000000000001" )
recipient = common . HexToAddress ( "095e7baea6a6c7c4c2dfeb977efac326af552d87" )
accesses = ethtypes . AccessList { { Address : addr , StorageKeys : [ ] common . Hash { { 0 } } } }
)
for i := uint64 ( 0 ) ; i < 500 ; i ++ {
var txdata ethtypes . TxData
switch i % 5 {
case 0 :
// Legacy tx.
txdata = & ethtypes . LegacyTx {
Nonce : i ,
To : & recipient ,
Gas : 1 ,
GasPrice : big . NewInt ( 2 ) ,
Data : [ ] byte ( "abcdef" ) ,
}
case 1 :
// Legacy tx contract creation.
txdata = & ethtypes . LegacyTx {
Nonce : i ,
Gas : 1 ,
GasPrice : big . NewInt ( 2 ) ,
Data : [ ] byte ( "abcdef" ) ,
}
case 2 :
// Tx with non-zero access list.
txdata = & ethtypes . AccessListTx {
ChainID : big . NewInt ( 1 ) ,
Nonce : i ,
To : & recipient ,
Gas : 123457 ,
GasPrice : big . NewInt ( 10 ) ,
AccessList : accesses ,
Data : [ ] byte ( "abcdef" ) ,
}
case 3 :
// Tx with empty access list.
txdata = & ethtypes . AccessListTx {
ChainID : big . NewInt ( 1 ) ,
Nonce : i ,
To : & recipient ,
Gas : 123457 ,
GasPrice : big . NewInt ( 10 ) ,
Data : [ ] byte ( "abcdef" ) ,
}
case 4 :
// Contract creation with access list.
txdata = & ethtypes . AccessListTx {
ChainID : big . NewInt ( 1 ) ,
Nonce : i ,
Gas : 123457 ,
GasPrice : big . NewInt ( 10 ) ,
AccessList : accesses ,
}
}
tx , err := ethtypes . SignNewTx ( key , signer , txdata )
if err != nil {
suite . T ( ) . Fatalf ( "could not sign transaction: %v" , err )
}
// RLP
parsedTx , err := encodeDecodeBinary ( tx )
if err != nil {
suite . T ( ) . Fatal ( err )
}
assertEqual ( parsedTx . AsTransaction ( ) , tx )
}
}
func encodeDecodeBinary ( tx * ethtypes . Transaction ) ( * types . MsgEthereumTx , error ) {
data , err := tx . MarshalBinary ( )
if err != nil {
return nil , fmt . Errorf ( "rlp encoding failed: %v" , err )
}
var parsedTx = & types . MsgEthereumTx { }
if err := parsedTx . UnmarshalBinary ( data ) ; err != nil {
return nil , fmt . Errorf ( "rlp decoding failed: %v" , err )
}
return parsedTx , nil
}
2021-10-26 11:13:27 +00:00
2021-11-02 11:20:19 +00:00
func assertEqual ( orig * ethtypes . Transaction , cpy * ethtypes . Transaction ) error {
// compare nonce, price, gaslimit, recipient, amount, payload, V, R, S
if want , got := orig . Hash ( ) , cpy . Hash ( ) ; want != got {
return fmt . Errorf ( "parsed tx differs from original tx, want %v, got %v" , want , got )
}
if want , got := orig . ChainId ( ) , cpy . ChainId ( ) ; want . Cmp ( got ) != 0 {
return fmt . Errorf ( "invalid chain id, want %d, got %d" , want , got )
}
if orig . AccessList ( ) != nil {
if ! reflect . DeepEqual ( orig . AccessList ( ) , cpy . AccessList ( ) ) {
return fmt . Errorf ( "access list wrong" )
}
}
return nil
2021-10-26 11:13:27 +00:00
}