From 036f7d62f418ce55fd845df1ef8fbf472314a6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Sun, 18 Sep 2022 10:56:34 -0300 Subject: [PATCH] Replace Decimal with Fraction Fractions are arbitrary-precision and will not cause truncated values. --- slither/slithir/variables/constant.py | 4 ++-- slither/utils/__init__.py | 3 --- slither/utils/arithmetic.py | 12 +++--------- slither/utils/integer_conversion.py | 10 +++++----- slither/visitors/expression/constants_folding.py | 6 +++--- 5 files changed, 13 insertions(+), 22 deletions(-) diff --git a/slither/slithir/variables/constant.py b/slither/slithir/variables/constant.py index 09a5ee34f..52cabf701 100644 --- a/slither/slithir/variables/constant.py +++ b/slither/slithir/variables/constant.py @@ -1,4 +1,4 @@ -from decimal import Decimal +from fractions import Fraction from functools import total_ordering from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint @@ -33,7 +33,7 @@ class Constant(SlithIRVariable): else: if val.isdigit(): self._type = ElementaryType("uint256") - self._val = int(Decimal(val)) + self._val = int(Fraction(val)) else: self._type = ElementaryType("string") self._val = val diff --git a/slither/utils/__init__.py b/slither/utils/__init__.py index 86427ca2e..e69de29bb 100644 --- a/slither/utils/__init__.py +++ b/slither/utils/__init__.py @@ -1,3 +0,0 @@ -from slither.utils.arithmetic import configure_decimal_precision - -configure_decimal_precision() \ No newline at end of file diff --git a/slither/utils/arithmetic.py b/slither/utils/arithmetic.py index 83c5be544..69684d103 100644 --- a/slither/utils/arithmetic.py +++ b/slither/utils/arithmetic.py @@ -1,13 +1,7 @@ -from decimal import Decimal, getcontext +from fractions import Fraction from slither.exceptions import SlitherException -def configure_decimal_precision(): - # Configure decimal precision high enough for 2 ** 256 - # Otherwise, large constant arithmetic may get truncated - if getcontext().prec < 80: - getcontext().prec = 80 - # pylint: disable=too-many-branches def convert_subdenomination( value: str, sub: str @@ -15,9 +9,9 @@ def convert_subdenomination( # to allow 0.1 ether conversion if value[0:2] == "0x": - decimal_value = Decimal(int(value, 16)) + decimal_value = Fraction(int(value, 16)) else: - decimal_value = Decimal(value) + decimal_value = Fraction(value) if sub == "wei": return int(decimal_value) if sub == "gwei": diff --git a/slither/utils/integer_conversion.py b/slither/utils/integer_conversion.py index 8481e8641..a410a956b 100644 --- a/slither/utils/integer_conversion.py +++ b/slither/utils/integer_conversion.py @@ -1,4 +1,4 @@ -from decimal import Decimal +from fractions import Fraction from typing import Union from slither.exceptions import SlitherError @@ -12,17 +12,17 @@ def convert_string_to_int(val: Union[str, int]) -> int: if "e" in val or "E" in val: base, expo = val.split("e") if "e" in val else val.split("E") - base, expo = Decimal(base), int(expo) + base, expo = Fraction(base), int(expo) # The resulting number must be < 2**256-1, otherwise solc # Would not be able to compile it # 10**77 is the largest exponent that fits # See https://github.com/ethereum/solidity/blob/9e61f92bd4d19b430cb8cb26f1c7cf79f1dff380/libsolidity/ast/Types.cpp#L1281-L1290 if expo > 77: - if base != Decimal(0): + if base != Fraction(0): raise SlitherError( f"{base}e{expo} is too large to fit in any Solidity integer size" ) return 0 - return int(Decimal(base) * Decimal(10**expo)) + return int(Fraction(base) * Fraction(10**expo)) - return int(Decimal(val)) + return int(Fraction(val)) diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 27ff9b592..2da1d7304 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -1,4 +1,4 @@ -from decimal import Decimal, InvalidOperation +from fractions import Fraction from slither.core.expressions import BinaryOperationType, Literal, UnaryOperationType from slither.utils.integer_conversion import convert_string_to_int from slither.visitors.expression.expression import ExpressionVisitor @@ -79,8 +79,8 @@ class ConstantFolding(ExpressionVisitor): def _post_literal(self, expression): try: - set_val(expression, Decimal(expression.value)) - except InvalidOperation: + set_val(expression, Fraction(expression.value)) + except ValueError: raise NotConstant def _post_assignement_operation(self, expression):