From d49a0a6e946ab0936457dbcec971d6657e3af4a2 Mon Sep 17 00:00:00 2001 From: Federico Kunze Date: Tue, 28 Sep 2021 11:36:32 +0200 Subject: [PATCH] evm: check height overflow --- types/validation.go | 10 ++++++ types/validation_test.go | 58 ++++++++++++++++++++++++++++++++ x/evm/keeper/state_transition.go | 8 ++++- 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/types/validation.go b/types/validation.go index 6e98f236c8..f9bcc908f6 100644 --- a/types/validation.go +++ b/types/validation.go @@ -2,6 +2,7 @@ package types import ( "bytes" + math "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 50a143f00b..86e387d443 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 3945d6d8d0..bece935210 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