laconicd/x/evm/types/dynamic_fee_tx_test.go
yihuang bc1d81c5e8
fix: Web3 RPC handlers panic (#702)
* Problem: Some Web3 RPC Handlers could panic

Closes: #701

Solution:
- return error rather than panic when decoding invalid tx

* add validation rules

* changelog
2021-10-26 13:13:27 +02:00

503 lines
8.7 KiB
Go

package types
import (
"math/big"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/suite"
"github.com/tharsis/ethermint/tests"
)
type TxDataTestSuite struct {
suite.Suite
sdkInt sdk.Int
uint64 uint64
bigInt *big.Int
sdkZeroInt sdk.Int
sdkMinusOneInt sdk.Int
invalidAddr string
addr common.Address
hexAddr string
}
func (suite *TxDataTestSuite) SetupTest() {
suite.sdkInt = sdk.NewInt(100)
suite.uint64 = suite.sdkInt.Uint64()
suite.bigInt = big.NewInt(1)
suite.sdkZeroInt = sdk.ZeroInt()
suite.sdkMinusOneInt = sdk.NewInt(-1)
suite.invalidAddr = "123456"
suite.addr = tests.GenerateAddress()
suite.hexAddr = suite.addr.Hex()
}
func TestTxDataTestSuite(t *testing.T) {
suite.Run(t, new(TxDataTestSuite))
}
func (suite *TxDataTestSuite) TestNewDynamicFeeTx() {
testCases := []struct {
name string
tx *ethtypes.Transaction
}{
{
"non-empty tx",
ethtypes.NewTx(&ethtypes.AccessListTx{ // TODO: change to DynamicFeeTx on Geth
Nonce: 1,
Data: []byte("data"),
Gas: 100,
Value: big.NewInt(1),
AccessList: ethtypes.AccessList{},
To: &suite.addr,
V: suite.bigInt,
R: suite.bigInt,
S: suite.bigInt,
}),
},
}
for _, tc := range testCases {
tx, err := newDynamicFeeTx(tc.tx)
suite.Require().NoError(err)
suite.Require().NotEmpty(tx)
suite.Require().Equal(uint8(2), tx.TxType())
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxCopy() {
tx := &DynamicFeeTx{}
txCopy := tx.Copy()
suite.Require().Equal(&DynamicFeeTx{}, txCopy)
// TODO: Test for different pointers
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetChainID() {
testCases := []struct {
name string
tx DynamicFeeTx
exp *big.Int
}{
{
"empty chainID",
DynamicFeeTx{
ChainID: nil,
},
nil,
},
{
"non-empty chainID",
DynamicFeeTx{
ChainID: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.GetChainID()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetAccessList() {
testCases := []struct {
name string
tx DynamicFeeTx
exp ethtypes.AccessList
}{
{
"empty accesses",
DynamicFeeTx{
Accesses: nil,
},
nil,
},
{
"nil",
DynamicFeeTx{
Accesses: NewAccessList(nil),
},
nil,
},
{
"non-empty accesses",
DynamicFeeTx{
Accesses: AccessList{
{
Address: suite.hexAddr,
StorageKeys: []string{},
},
},
},
ethtypes.AccessList{
{
Address: suite.addr,
StorageKeys: []common.Hash{},
},
},
},
}
for _, tc := range testCases {
actual := tc.tx.GetAccessList()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetData() {
testCases := []struct {
name string
tx DynamicFeeTx
}{
{
"non-empty transaction",
DynamicFeeTx{
Data: nil,
},
},
}
for _, tc := range testCases {
actual := tc.tx.GetData()
suite.Require().Equal(tc.tx.Data, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetGas() {
testCases := []struct {
name string
tx DynamicFeeTx
exp uint64
}{
{
"non-empty gas",
DynamicFeeTx{
GasLimit: suite.uint64,
},
suite.uint64,
},
}
for _, tc := range testCases {
actual := tc.tx.GetGas()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetGasPrice() {
testCases := []struct {
name string
tx DynamicFeeTx
exp *big.Int
}{
{
"non-empty gasFeeCap",
DynamicFeeTx{
GasFeeCap: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.GetGasPrice()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetGasTipCap() {
testCases := []struct {
name string
tx DynamicFeeTx
exp *big.Int
}{
{
"empty gasTipCap",
DynamicFeeTx{
GasTipCap: nil,
},
nil,
},
{
"non-empty gasTipCap",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.GetGasTipCap()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetGasFeeCap() {
testCases := []struct {
name string
tx DynamicFeeTx
exp *big.Int
}{
{
"empty gasFeeCap",
DynamicFeeTx{
GasFeeCap: nil,
},
nil,
},
{
"non-empty gasFeeCap",
DynamicFeeTx{
GasFeeCap: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.GetGasFeeCap()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetValue() {
testCases := []struct {
name string
tx DynamicFeeTx
exp *big.Int
}{
{
"empty amount",
DynamicFeeTx{
Amount: nil,
},
nil,
},
{
"non-empty amount",
DynamicFeeTx{
Amount: &suite.sdkInt,
},
(&suite.sdkInt).BigInt(),
},
}
for _, tc := range testCases {
actual := tc.tx.GetValue()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetNonce() {
testCases := []struct {
name string
tx DynamicFeeTx
exp uint64
}{
{
"non-empty nonce",
DynamicFeeTx{
Nonce: suite.uint64,
},
suite.uint64,
},
}
for _, tc := range testCases {
actual := tc.tx.GetNonce()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxGetTo() {
testCases := []struct {
name string
tx DynamicFeeTx
exp *common.Address
}{
{
"empty suite.address",
DynamicFeeTx{
To: "",
},
nil,
},
{
"non-empty suite.address",
DynamicFeeTx{
To: suite.hexAddr,
},
&suite.addr,
},
}
for _, tc := range testCases {
actual := tc.tx.GetTo()
suite.Require().Equal(tc.exp, actual, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxSetSignatureValues() {
testCases := []struct {
name string
chainID *big.Int
r *big.Int
v *big.Int
s *big.Int
}{
{
"empty values",
nil,
nil,
nil,
nil,
},
{
"non-empty values",
suite.bigInt,
suite.bigInt,
suite.bigInt,
suite.bigInt,
},
}
for _, tc := range testCases {
tx := &DynamicFeeTx{}
tx.SetSignatureValues(tc.chainID, tc.v, tc.r, tc.s)
v, r, s := tx.GetRawSignatureValues()
chainID := tx.GetChainID()
suite.Require().Equal(tc.v, v, tc.name)
suite.Require().Equal(tc.r, r, tc.name)
suite.Require().Equal(tc.s, s, tc.name)
suite.Require().Equal(tc.chainID, chainID, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxValidate() {
testCases := []struct {
name string
tx DynamicFeeTx
expError bool
}{
{
"empty",
DynamicFeeTx{},
true,
},
{
"gas tip cap is nil",
DynamicFeeTx{
GasTipCap: nil,
},
true,
},
{
"gas fee cap is nil",
DynamicFeeTx{
GasTipCap: &suite.sdkZeroInt,
},
true,
},
{
"gas tip cap is negative",
DynamicFeeTx{
GasTipCap: &suite.sdkMinusOneInt,
GasFeeCap: &suite.sdkZeroInt,
},
true,
},
{
"gas tip cap is negative",
DynamicFeeTx{
GasTipCap: &suite.sdkZeroInt,
GasFeeCap: &suite.sdkMinusOneInt,
},
true,
},
{
"gas fee cap < gas tip cap",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
GasFeeCap: &suite.sdkZeroInt,
},
true,
},
{
"amount is negative",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
GasFeeCap: &suite.sdkInt,
Amount: &suite.sdkMinusOneInt,
},
true,
},
{
"to suite.address is invalid",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
GasFeeCap: &suite.sdkInt,
Amount: &suite.sdkInt,
To: suite.invalidAddr,
},
true,
},
{
"chain ID not present on AccessList txs",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
GasFeeCap: &suite.sdkInt,
Amount: &suite.sdkInt,
To: suite.hexAddr,
ChainID: nil,
},
true,
},
{
"no errors",
DynamicFeeTx{
GasTipCap: &suite.sdkInt,
GasFeeCap: &suite.sdkInt,
Amount: &suite.sdkInt,
To: suite.hexAddr,
ChainID: &suite.sdkInt,
},
false,
},
}
for _, tc := range testCases {
err := tc.tx.Validate()
if tc.expError {
suite.Require().Error(err, tc.name)
continue
}
suite.Require().NoError(err, tc.name)
}
}
func (suite *TxDataTestSuite) TestDynamicFeeTxFeeCost() {
tx := &DynamicFeeTx{}
suite.Require().Panics(func() { tx.Fee() }, "should panic")
suite.Require().Panics(func() { tx.Cost() }, "should panic")
}