From 83627b996703164430c98e9758059530e02bef54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Kunze=20K=C3=BCllmer?= <31522760+fedekunze@users.noreply.github.com> Date: Tue, 28 Sep 2021 11:48:11 +0200 Subject: [PATCH] evm: check height overflow (#597) * evm: check height overflow * rm * c++ --- CHANGELOG.md | 1 + types/validation.go | 10 ++++++ types/validation_test.go | 58 ++++++++++++++++++++++++++++++++ x/evm/keeper/state_transition.go | 8 ++++- 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ab37df2..e5ee5796 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +* (evm) [tharsis#597](https://github.com/tharsis/ethermint/pull/597) Check for `uint64` -> `int64` block height overflow on `GetHashFn` * (evm) [tharsis#579](https://github.com/tharsis/ethermint/pull/579) Update `DeriveChainID` function to handle `v` signature values `< 35`. * (encoding) [tharsis#478](https://github.com/tharsis/ethermint/pull/478) Register `Evidence` to amino codec. * (rpc) [tharsis#478](https://github.com/tharsis/ethermint/pull/481) Getting the node configuration when calling the `miner` rpc methods. diff --git a/types/validation.go b/types/validation.go index 6e98f236..15e27ee3 100644 --- a/types/validation.go +++ b/types/validation.go @@ -2,6 +2,7 @@ package types import ( "bytes" + "math" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/common" @@ -27,3 +28,12 @@ func ValidateAddress(address string) error { } return nil } + +// SafeInt64 checks for overflows while casting a uint64 to int64 value. +func SafeInt64(value uint64) (int64, error) { + if value > uint64(math.MaxInt64) { + return 0, sdkerrors.Wrapf(sdkerrors.ErrInvalidHeight, "uint64 value %v cannot exceed %v", value, int64(math.MaxInt64)) + } + + return int64(value), nil +} diff --git a/types/validation_test.go b/types/validation_test.go index 50a143f0..86e387d4 100644 --- a/types/validation_test.go +++ b/types/validation_test.go @@ -5,6 +5,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/tharsis/ethermint/tests" ) func TestIsEmptyHash(t *testing.T) { @@ -52,3 +53,60 @@ func TestIsZeroAddress(t *testing.T) { require.Equal(t, tc.expEmpty, IsZeroAddress(tc.address), tc.name) } } + +func TestValidateAddress(t *testing.T) { + testCases := []struct { + name string + address string + expError bool + }{ + { + "empty string", "", true, + }, + { + "invalid address", "0x", true, + }, + { + "zero address", common.Address{}.String(), false, + }, + { + "valid address", tests.GenerateAddress().Hex(), false, + }, + } + + for _, tc := range testCases { + err := ValidateAddress(tc.address) + + if tc.expError { + require.Error(t, err, tc.name) + } else { + require.NoError(t, err, tc.name) + } + } +} + +func TestSafeInt64(t *testing.T) { + testCases := []struct { + name string + value uint64 + expError bool + }{ + { + "no overflow", 10, false, + }, + { + "overflow", 18446744073709551615, true, + }, + } + + for _, tc := range testCases { + value, err := SafeInt64(tc.value) + if tc.expError { + require.Error(t, err, tc.name) + continue + } + + require.NoError(t, err, tc.name) + require.Equal(t, int64(tc.value), value, tc.name) + } +} diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index 3945d6d8..bece9352 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -66,8 +66,14 @@ func (k Keeper) VMConfig(msg core.Message, params types.Params, tracer vm.Tracer // 3. The requested height is from a height greater than the latest one func (k Keeper) GetHashFn() vm.GetHashFunc { return func(height uint64) common.Hash { - h := int64(height) ctx := k.Ctx() + + h, err := ethermint.SafeInt64(height) + if err != nil { + k.Logger(ctx).Error("failed to cast height to int64", "error", err) + return common.Hash{} + } + switch { case ctx.BlockHeight() == h: // Case 1: The requested height matches the one from the context so we can retrieve the header