package types

import (
	"math"
	"testing"

	"github.com/tendermint/go-amino"

	"github.com/stretchr/testify/require"

	sdk "github.com/okex/exchain/libs/cosmos-sdk/types"

	"github.com/ethereum/go-ethereum/common"
)

var defaultEIP150Hash = common.Hash{}.String()

func TestChainConfigValidate(t *testing.T) {
	testCases := []struct {
		name     string
		config   ChainConfig
		expError bool
	}{
		{"default", DefaultChainConfig(), false},
		{
			"valid",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.OneInt(),
				YoloV2Block:         sdk.OneInt(),
				EWASMBlock:          sdk.OneInt(),
			},
			false,
		},
		{
			"empty",
			ChainConfig{},
			true,
		},
		{
			"invalid HomesteadBlock",
			ChainConfig{
				HomesteadBlock: sdk.Int{},
			},
			true,
		},
		{
			"invalid DAOForkBlock",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.Int{},
			},
			true,
		},
		{
			"invalid EIP150Block",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.Int{},
			},
			true,
		},
		{
			"invalid EIP150Hash",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.OneInt(),
				EIP150Hash:     "  ",
			},
			true,
		},
		{
			"invalid EIP155Block",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.OneInt(),
				EIP150Hash:     defaultEIP150Hash,
				EIP155Block:    sdk.Int{},
			},
			true,
		},
		{
			"invalid EIP158Block",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.OneInt(),
				EIP150Hash:     defaultEIP150Hash,
				EIP155Block:    sdk.OneInt(),
				EIP158Block:    sdk.Int{},
			},
			true,
		},
		{
			"invalid ByzantiumBlock",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.OneInt(),
				EIP150Hash:     defaultEIP150Hash,
				EIP155Block:    sdk.OneInt(),
				EIP158Block:    sdk.OneInt(),
				ByzantiumBlock: sdk.Int{},
			},
			true,
		},
		{
			"invalid ConstantinopleBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.Int{},
			},
			true,
		},
		{
			"invalid PetersburgBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.Int{},
			},
			true,
		},
		{
			"invalid IstanbulBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.Int{},
			},
			true,
		},
		{
			"invalid MuirGlacierBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.Int{},
			},
			true,
		},
		{
			"invalid YoloV2Block",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.OneInt(),
				YoloV2Block:         sdk.Int{},
			},
			true,
		},
		{
			"invalid EWASMBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.OneInt(),
				YoloV2Block:         sdk.OneInt(),
				EWASMBlock:          sdk.Int{},
			},
			true,
		},
		{
			"invalid hash",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          "0x1234567890abcdef",
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.OneInt(),
				YoloV2Block:         sdk.OneInt(),
				EWASMBlock:          sdk.OneInt(),
			},
			true,
		},
	}

	for _, tc := range testCases {
		err := tc.config.Validate()

		if tc.expError {
			require.Error(t, err, tc.name)
		} else {
			require.NoError(t, err, tc.name)
		}
	}
}

func TestChainConfig_String(t *testing.T) {
	configStr := `homestead_block: "0"
dao_fork_block: "0"
dao_fork_support: true
eip150_block: "0"
eip150_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
eip155_block: "0"
eip158_block: "0"
byzantium_block: "0"
constantinople_block: "0"
petersburg_block: "0"
istanbul_block: "0"
muir_glacier_block: "0"
yoloV2_block: "-1"
ewasm_block: "-1"
`
	require.Equal(t, configStr, DefaultChainConfig().String())
}

func TestChainConfigAmino(t *testing.T) {
	testCases := []ChainConfig{
		{},
		{
			DAOForkSupport: true,
			EIP150Hash:     "EIP150Hash",
		},
		{
			sdk.NewInt(0),
			sdk.NewInt(1),
			false,
			sdk.NewInt(2),
			"test",
			sdk.NewInt(3),
			sdk.NewInt(4),
			sdk.NewInt(5),
			sdk.NewInt(6),
			sdk.NewInt(7),
			sdk.NewInt(8),
			sdk.NewInt(9),
			sdk.NewInt(10),
			sdk.NewInt(11),
		},
		{
			HomesteadBlock:      sdk.NewInt(math.MaxInt64),
			DAOForkBlock:        sdk.NewInt(math.MaxInt64),
			EIP150Block:         sdk.NewInt(math.MaxInt64),
			EIP155Block:         sdk.NewInt(math.MaxInt64),
			EIP158Block:         sdk.NewInt(math.MaxInt64),
			ByzantiumBlock:      sdk.NewInt(math.MaxInt64),
			ConstantinopleBlock: sdk.NewInt(math.MaxInt64),
			PetersburgBlock:     sdk.NewInt(math.MaxInt64),
			IstanbulBlock:       sdk.NewInt(math.MaxInt64),
			MuirGlacierBlock:    sdk.NewInt(math.MaxInt64),
			YoloV2Block:         sdk.NewInt(math.MaxInt64),
			EWASMBlock:          sdk.NewInt(math.MaxInt64),
		},
		{
			HomesteadBlock:      sdk.NewInt(math.MinInt64),
			DAOForkBlock:        sdk.NewInt(math.MinInt64),
			EIP150Block:         sdk.NewInt(math.MinInt64),
			EIP155Block:         sdk.NewInt(math.MinInt64),
			EIP158Block:         sdk.NewInt(math.MinInt64),
			ByzantiumBlock:      sdk.NewInt(math.MinInt64),
			ConstantinopleBlock: sdk.NewInt(math.MinInt64),
			PetersburgBlock:     sdk.NewInt(math.MinInt64),
			IstanbulBlock:       sdk.NewInt(math.MinInt64),
			MuirGlacierBlock:    sdk.NewInt(math.MinInt64),
			YoloV2Block:         sdk.NewInt(math.MinInt64),
			EWASMBlock:          sdk.NewInt(math.MinInt64),
		},
	}

	cdc := amino.NewCodec()
	RegisterCodec(cdc)

	for _, chainConfig := range testCases {
		expectData, err := cdc.MarshalBinaryBare(chainConfig)
		require.NoError(t, err)

		var expectValue ChainConfig
		err = cdc.UnmarshalBinaryBare(expectData, &expectValue)
		require.NoError(t, err)

		var actualValue ChainConfig
		err = actualValue.UnmarshalFromAmino(cdc, expectData[4:])
		require.NoError(t, err)

		require.EqualValues(t, expectValue, actualValue)

		v, err := cdc.UnmarshalBinaryBareWithRegisteredUnmarshaller(expectData, &actualValue)
		require.NoError(t, err)
		actualValue = v.(ChainConfig)
		require.EqualValues(t, expectValue, actualValue)
	}
}
package types

import (
	"math"
	"testing"

	"github.com/tendermint/go-amino"

	"github.com/stretchr/testify/require"

	sdk "github.com/okex/exchain/libs/cosmos-sdk/types"

	"github.com/ethereum/go-ethereum/common"
)

var defaultEIP150Hash = common.Hash{}.String()

func TestChainConfigValidate(t *testing.T) {
	testCases := []struct {
		name     string
		config   ChainConfig
		expError bool
	}{
		{"default", DefaultChainConfig(), false},
		{
			"valid",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.OneInt(),
				YoloV2Block:         sdk.OneInt(),
				EWASMBlock:          sdk.OneInt(),
			},
			false,
		},
		{
			"empty",
			ChainConfig{},
			true,
		},
		{
			"invalid HomesteadBlock",
			ChainConfig{
				HomesteadBlock: sdk.Int{},
			},
			true,
		},
		{
			"invalid DAOForkBlock",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.Int{},
			},
			true,
		},
		{
			"invalid EIP150Block",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.Int{},
			},
			true,
		},
		{
			"invalid EIP150Hash",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.OneInt(),
				EIP150Hash:     "  ",
			},
			true,
		},
		{
			"invalid EIP155Block",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.OneInt(),
				EIP150Hash:     defaultEIP150Hash,
				EIP155Block:    sdk.Int{},
			},
			true,
		},
		{
			"invalid EIP158Block",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.OneInt(),
				EIP150Hash:     defaultEIP150Hash,
				EIP155Block:    sdk.OneInt(),
				EIP158Block:    sdk.Int{},
			},
			true,
		},
		{
			"invalid ByzantiumBlock",
			ChainConfig{
				HomesteadBlock: sdk.OneInt(),
				DAOForkBlock:   sdk.OneInt(),
				EIP150Block:    sdk.OneInt(),
				EIP150Hash:     defaultEIP150Hash,
				EIP155Block:    sdk.OneInt(),
				EIP158Block:    sdk.OneInt(),
				ByzantiumBlock: sdk.Int{},
			},
			true,
		},
		{
			"invalid ConstantinopleBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.Int{},
			},
			true,
		},
		{
			"invalid PetersburgBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.Int{},
			},
			true,
		},
		{
			"invalid IstanbulBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.Int{},
			},
			true,
		},
		{
			"invalid MuirGlacierBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.Int{},
			},
			true,
		},
		{
			"invalid YoloV2Block",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.OneInt(),
				YoloV2Block:         sdk.Int{},
			},
			true,
		},
		{
			"invalid EWASMBlock",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          defaultEIP150Hash,
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.OneInt(),
				YoloV2Block:         sdk.OneInt(),
				EWASMBlock:          sdk.Int{},
			},
			true,
		},
		{
			"invalid hash",
			ChainConfig{
				HomesteadBlock:      sdk.OneInt(),
				DAOForkBlock:        sdk.OneInt(),
				EIP150Block:         sdk.OneInt(),
				EIP150Hash:          "0x1234567890abcdef",
				EIP155Block:         sdk.OneInt(),
				EIP158Block:         sdk.OneInt(),
				ByzantiumBlock:      sdk.OneInt(),
				ConstantinopleBlock: sdk.OneInt(),
				PetersburgBlock:     sdk.OneInt(),
				IstanbulBlock:       sdk.OneInt(),
				MuirGlacierBlock:    sdk.OneInt(),
				YoloV2Block:         sdk.OneInt(),
				EWASMBlock:          sdk.OneInt(),
			},
			true,
		},
	}

	for _, tc := range testCases {
		err := tc.config.Validate()

		if tc.expError {
			require.Error(t, err, tc.name)
		} else {
			require.NoError(t, err, tc.name)
		}
	}
}

func TestChainConfig_String(t *testing.T) {
	configStr := `homestead_block: "0"
dao_fork_block: "0"
dao_fork_support: true
eip150_block: "0"
eip150_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
eip155_block: "0"
eip158_block: "0"
byzantium_block: "0"
constantinople_block: "0"
petersburg_block: "0"
istanbul_block: "0"
muir_glacier_block: "0"
yoloV2_block: "-1"
ewasm_block: "-1"
`
	require.Equal(t, configStr, DefaultChainConfig().String())
}

func TestChainConfigAmino(t *testing.T) {
	testCases := []ChainConfig{
		{},
		{
			DAOForkSupport: true,
			EIP150Hash:     "EIP150Hash",
		},
		{
			sdk.NewInt(0),
			sdk.NewInt(1),
			false,
			sdk.NewInt(2),
			"test",
			sdk.NewInt(3),
			sdk.NewInt(4),
			sdk.NewInt(5),
			sdk.NewInt(6),
			sdk.NewInt(7),
			sdk.NewInt(8),
			sdk.NewInt(9),
			sdk.NewInt(10),
			sdk.NewInt(11),
		},
		{
			HomesteadBlock:      sdk.NewInt(math.MaxInt64),
			DAOForkBlock:        sdk.NewInt(math.MaxInt64),
			EIP150Block:         sdk.NewInt(math.MaxInt64),
			EIP155Block:         sdk.NewInt(math.MaxInt64),
			EIP158Block:         sdk.NewInt(math.MaxInt64),
			ByzantiumBlock:      sdk.NewInt(math.MaxInt64),
			ConstantinopleBlock: sdk.NewInt(math.MaxInt64),
			PetersburgBlock:     sdk.NewInt(math.MaxInt64),
			IstanbulBlock:       sdk.NewInt(math.MaxInt64),
			MuirGlacierBlock:    sdk.NewInt(math.MaxInt64),
			YoloV2Block:         sdk.NewInt(math.MaxInt64),
			EWASMBlock:          sdk.NewInt(math.MaxInt64),
		},
		{
			HomesteadBlock:      sdk.NewInt(math.MinInt64),
			DAOForkBlock:        sdk.NewInt(math.MinInt64),
			EIP150Block:         sdk.NewInt(math.MinInt64),
			EIP155Block:         sdk.NewInt(math.MinInt64),
			EIP158Block:         sdk.NewInt(math.MinInt64),
			ByzantiumBlock:      sdk.NewInt(math.MinInt64),
			ConstantinopleBlock: sdk.NewInt(math.MinInt64),
			PetersburgBlock:     sdk.NewInt(math.MinInt64),
			IstanbulBlock:       sdk.NewInt(math.MinInt64),
			MuirGlacierBlock:    sdk.NewInt(math.MinInt64),
			YoloV2Block:         sdk.NewInt(math.MinInt64),
			EWASMBlock:          sdk.NewInt(math.MinInt64),
		},
	}

	cdc := amino.NewCodec()
	RegisterCodec(cdc)

	for _, chainConfig := range testCases {
		expectData, err := cdc.MarshalBinaryBare(chainConfig)
		require.NoError(t, err)

		var expectValue ChainConfig
		err = cdc.UnmarshalBinaryBare(expectData, &expectValue)
		require.NoError(t, err)

		var actualValue ChainConfig
		err = actualValue.UnmarshalFromAmino(cdc, expectData[4:])
		require.NoError(t, err)

		require.EqualValues(t, expectValue, actualValue)

		v, err := cdc.UnmarshalBinaryBareWithRegisteredUnmarshaller(expectData, &actualValue)
		require.NoError(t, err)
		actualValue = v.(ChainConfig)
		require.EqualValues(t, expectValue, actualValue)
	}
}
