Repository: vyperlang/vyper

Issue:
Incorrect 'less than' comparison.
### What's your issue about?

In the contract below, the `lessThanMaxUint` function returns false incorrectly.

I've also tested this with smaller numbers (ie. `20 < 30`) and the behaviour is correct, so I suspect there is an issue with this operation on uint256 vs. int128.

```
max_uint_256: public(uint256)

@public
def __init__():
    self.max_uint_256 = 2*(2**255-1)+1

@public 
def lessThanMaxUint() -> (bool):
  return 20 < self.max_uint_256 # returns false

@public 
def notEqualToMaxUint() -> (bool):
  return 20 != self.max_uint_256 # returns true
```



Discussion:

Resolving patch:
diff --git a/vyper/parser/expr.py b/vyper/parser/expr.py
--- a/vyper/parser/expr.py
+++ b/vyper/parser/expr.py
@@ -458,6 +458,19 @@ def build_in_comparator(self):
 
         return o
 
+    @staticmethod
+    def _signed_to_unsigned_comparision_op(op):
+        translation_map = {
+            'sgt': 'gt',
+            'sge': 'ge',
+            'sle': 'le',
+            'slt': 'lt',
+        }
+        if op in translation_map:
+            return translation_map[op]
+        else:
+            return op
+
     def compare(self):
         left = Expr.parse_value_expr(self.expr.left, self.context)
         right = Expr.parse_value_expr(self.expr.comparators[0], self.context)
@@ -521,10 +534,13 @@ def load_bytearray(side):
                 comparison_allowed = True
             elif right.typ.is_literal and SizeLimits.in_bounds(left_type, right.value):
                 comparison_allowed = True
+            op = self._signed_to_unsigned_comparision_op(op)
 
             if comparison_allowed:
                 return LLLnode.from_list([op, left, right], typ='bool', pos=getpos(self.expr))
 
+        elif {left_type, right_type} == {'uint256', 'uint256'}:
+            op = self._signed_to_unsigned_comparision_op(op)
         elif (left_type in ('decimal', 'int128') or right_type in ('decimal', 'int128')) and left_type != right_type:
             raise TypeMismatchException(
                 'Implicit conversion from {} to {} disallowed, please convert.'.format(left_type, right_type),


Test patch:
diff --git a/tests/parser/types/numbers/test_uint256.py b/tests/parser/types/numbers/test_uint256.py
--- a/tests/parser/types/numbers/test_uint256.py
+++ b/tests/parser/types/numbers/test_uint256.py
@@ -183,3 +183,41 @@ def test() -> uint256:
 
     c = get_contract_with_gas_estimation(modexper)
     assert c.test() == 340282366920938463463374607431768211459
+
+
+def test_uint256_comparison(get_contract_with_gas_estimation):
+    code = """
+max_uint_256: public(uint256)
+
+@public
+def __init__():
+    self.max_uint_256 = 2*(2**255-1)+1
+
+@public
+def max_lt() -> (bool):
+  return 30 < self.max_uint_256
+
+@public
+def max_lte() -> (bool):
+  return 30  <= self.max_uint_256
+
+@public
+def max_gte() -> (bool):
+  return 30 >=  self.max_uint_256
+
+@public
+def max_gt() -> (bool):
+  return 30 > self.max_uint_256
+
+@public
+def max_ne() -> (bool):
+  return 30 != self.max_uint_256
+    """
+
+    c = get_contract_with_gas_estimation(code)
+
+    assert c.max_lt() is True
+    assert c.max_lte() is True
+    assert c.max_gte() is False
+    assert c.max_gt() is False
+    assert c.max_ne() is True