Vyper: `outsize` param of `raw_call` doesn't accept a constant.

Created on 5 Jan 2019  路  7Comments  路  Source: vyperlang/vyper

Version Information

  • vyper Version: 1.0.0b6

What's your issue about?

outsize param of raw_call doesn't accept a constant.

TEST_C: constant(int128) = 1
TEST_WEI: constant(uint256(wei)) = 1

# Expecting num_literal for argument 'outsize' of raw_call
@private
def test():
    raw_call(0x0000000000000000000000000000000000000005, 'hello', outsize=TEST_C, gas=2000)

# Compiled!
@private
def test1():
    # Expecting num_literal for argument 'outsize' of raw_call
    raw_call(0x0000000000000000000000000000000000000005, 'hello', outsize=256, gas=TEST_WEI)

How can it be fixed?

Cute Animal Picture

image

bug

All 7 comments

Here is the culprit I think @nrryuya

https://github.com/ethereum/vyper/blob/master/vyper/functions/signature.py#L81

Which appears to be a strange piece of code
we have this if statement checking :

if len(expected_arg_typelist) == 1:
        raise TypeMismatchException("Expecting %s for argument %r of %s" %
                                    (expected_arg, index, function_name), arg)

which appears to be the exact error
But what I find strange is the else clause

 else:
        raise TypeMismatchException("Expecting one of %r for argument %r of %s" %
                                    (expected_arg_typelist, index, function_name), arg)
        return arg.id

It seems if we reach this code block it will get an exception in either case, so I am wondering if it is meant to return before that

I'v dug into the code and it appears that the arg isin't getting validated as a ast.Num type.

It appears to go through the args with process_arg until it eventual gets to our num_literal, it correctly sees its a num_literal but then there is a check
if isinstance(arg, ast.Num) and get_original_if_0_prefixed(arg, context) is None:

the first part of the check always is false for me, as the type of arg here is ast.Name

Edit:
Also here we have a check to ensure a constant is of type ast.Name https://github.com/ethereum/vyper/blob/master/vyper/signatures/function_signature.py#L102

could this be the culprit ?

@Ryan-Gordon Thank you!

I found range() has a similar issue.

CONST: constant(uint256) = 8

@public
@constant
def test():
    # "Range only accepts literal (constant) values"
    for i in range(CONST / 4):
        pass

Although, range(CONST) works well.

@Ryan-Gordon you were correct about the nature of the problem. I have created a fix with additional work to make the use of constant types easier. @nrryuya if you could review the PR / test the PR that would be great :)

@jacqueswww thanks for confirming.

To understand your change I looked over the PR and

if context.is_constant_of_base_type(arg, ('uint256', 'int128')):
                 return context.get_constant(arg.id).value

so would it be right to say this piece of code checks the base_type (as shown) and then acquires the value by using the id of the ast.Name to get a ast.Num representation ?

Great work !

@jacqueswww @Ryan-Gordon
Thank you!

I tested #1180 and it worked for the original issue ;)

How about the one in https://github.com/ethereum/vyper/issues/1178#issuecomment-451620170 ?
Something like range(CONST / 4) or raw_call(A, 'hello', outsize=CONST / 5, gas=G) are intentinally prohibited?

@nrryuya I am still working on #1178 will let you know how it goes.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lsaether picture lsaether  路  4Comments

jakerockland picture jakerockland  路  4Comments

jacqueswww picture jacqueswww  路  4Comments

ben-kaufman picture ben-kaufman  路  4Comments

pipermerriam picture pipermerriam  路  3Comments