-
-
Notifications
You must be signed in to change notification settings - Fork 804
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Num256 with natural expressions. #355
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good, encompasses all the changes I would expect
if o.typ.typ == 'num': | ||
return LLLnode.from_list(['clamp', ['mload', MINNUM_POS], o, ['mload', MAXNUM_POS]], typ=o.typ, pos=getpos(expr)) | ||
elif o.typ.typ == 'decimal': | ||
return LLLnode.from_list(['clamp', ['mload', MINDECIMAL_POS], o, ['mload', MAXDECIMAL_POS]], typ=o.typ, pos=getpos(expr)) | ||
elif o.typ.typ == 'num256': | ||
return o |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can return o
directly here because there is no need for an overflow check? Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fubuloubu yes that was my understanding, ie. the full 32byte has been occupied by a single variable, therefore can't overflow. But I could be wrong ? I worked from the LLL output of num256_
functions - they definitely don't have any sort of clamping - If we do require it, let me know and I will add it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jacqueswww I believe you should add clamping so that this test case results in TransactionFailed
(right now it passes). Clamping here is necessary because it checks user input (which can result in a number more than 2**256-1).
"""
def test_num_256_overflow():
num256_code = """
def _num256_mul(x: num256, y: num256) -> num256:
return num256_mul(x, y)
c = get_contract_with_gas_estimation(num256_code)
x = 2 ** 256 - 1
assert c._num256_mul(x, x) == 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect @DavidKnott!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great stuff thanks for the info, will add soonest ;)
@@ -627,6 +627,8 @@ def parse_expr(expr, context): | |||
new_unit = combine_units(left.typ.unit, right.typ.unit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually about L623 above. Does it make sense not to implement cross-type operations? I believe it might for num256
|decimal
, as we might have data loss there, but num
|num256
can occur fine withouth data loss (implicit conversion of num
to num256
).
Same below L656 (in updated file) for division. Does it make sense not to have cross-type division? I'm leaning towards yes, but discuss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fubuloubu sure I was going to do cross-type operations as a seperate PR. For the time being the compiler will throw an error with any type of cross-type operation. If you prefer I can do num | num256
as part of this PR/branch ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think doing it as a separate PR would work best. There are some subtle considerations that I think warrant a second PR. I'll add an issue to remind ourselves of this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool thanks :) 👍
@@ -645,6 +647,8 @@ def parse_expr(expr, context): | |||
new_unit = combine_units(left.typ.unit, right.typ.unit, div=True) | |||
if rtyp == 'num': | |||
o = LLLnode.from_list(['sdiv', left, ['clamp_nonzero', right]], typ=BaseType(ltyp, new_unit), pos=getpos(expr)) | |||
elif ltyp == rtyp == 'num256': | |||
o = LLLnode.from_list(['div', left, right], typ=BaseType('num256', new_unit), pos=getpos(expr)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a potential for data loss here. I'm not sure if there's a way to avoid it (such as above for num
, which also has potential data loss). Discuss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And by data loss, I mean decimal point flooring (or does it round? @DavidKnott )
Closing as this is to be replaced by a specific type or decorator that casts (and clamps) to num. |
- What I did
Added support for num256 to be evaluated without using builtin num256_xxx functions.
- How I did it
- How to verify it
Check the test, one can also evaluate the LLL output with the following example (or similar):
- Description for the changelog
Allows evaluating of basic arithmetic expressions using uint256 and uint256.
- Cute Animal Picture