vyperlang / vyper

Pythonic Smart Contract Language for the EVM
https://vyperlang.org
Other
4.86k stars 793 forks source link

IndexError: list index out of range #2250

Closed JhonnyJason closed 2 years ago

JhonnyJason commented 3 years ago

Version Information

What's your issue about?

Following code produces this Compile Error and it fails to compile: IndexError: list index out of range

# @version ^0.2.8

INITIAL_MINTABLE_PRO_ETH: constant(uint256) = 666
INITIAL_MINT_CEILING: constant(uint256) = 100000000000000000000000 #100k

############################################################
struct Parameters:
    mintableProETH: Bytes[2]
    mintCeiling: Bytes[15]

############################################################
params: Parameters

############################################################
@external
def __init__():
    self.params.mintableProETH = slice(convert(INITIAL_MINTABLE_PRO_ETH, bytes32), 30, 2)
    self.params.mintCeiling = slice(convert(INITIAL_MINT_CEILING, bytes32), 17, 15)
   ## This also fails in the same way
   #  self.params.mintableProETH = slice(convert(666, bytes32), 30, 2)
   #  self.params.mintCeiling = slice(convert(100000000000000000000000, bytes32), 17, 15)

How can it be fixed?

I don't know what really is the cause of this. I do have a workaround though.

INITIAL_MINTABLE_PRO_ETH: constant(Bytes[2]) = 0x029a # 666 -> hex
INITIAL_MINT_CEILING: constant(Bytes[15]) = 0x152d02c7e14af6800000 # 100k -> hex

############################################################
struct Parameters:
    mintableProETH: Bytes[2]
    mintCeiling: Bytes[15]

############################################################
params: Parameters

############################################################
@external
def __init__(_name: String[26], _symbol: String[6]):
    self.params.mintableProETH = INITIAL_MINTABLE_PRO_ETH
    self.params.mintCeiling = INITIAL_MINT_CEILING

Cheers!

agroce commented 3 years ago

This may be related to something I'm seeing in fuzzing. Using the compiler without a file to compile strings, I get:

>>> vyper.compiler.compile_code('\r[[]]\ndef _(e:[],l:[]):\n    """"""""""""""""""""""""""""""""""""""""""""""""""""""\n    f.n()')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/__init__.py", line 151, in compile_code
    return compile_codes(
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/opcodes.py", line 222, in _wrapper
    return fn(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/__init__.py", line 110, in compile_codes
    raise exc
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/__init__.py", line 105, in compile_codes
    out[contract_name][output_format] = OUTPUT_FORMATS[output_format](compiler_data)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/output.py", line 138, in build_bytecode_output
    return f"0x{compiler_data.bytecode.hex()}"
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/phases.py", line 126, in bytecode
    self._bytecode = generate_bytecode(self.assembly)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/phases.py", line 114, in assembly
    self._assembly = generate_assembly(self.lll_nodes)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/phases.py", line 102, in lll_nodes
    self._gen_lll()
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/phases.py", line 97, in _gen_lll
    self._lll_nodes, self._lll_runtime = generate_lll_nodes(self.global_ctx)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/phases.py", line 90, in global_ctx
    self.vyper_module_folded, self.interface_codes
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/phases.py", line 81, in vyper_module_folded
    self._vyper_module_folded = generate_folded_ast(self.vyper_module)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/phases.py", line 74, in vyper_module
    self._vyper_module = generate_ast(self.source_code, self.source_id, self.contract_name)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/compiler/phases.py", line 154, in generate_ast
    return vy_ast.parse_to_ast(source_code, source_id, contract_name)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/ast/utils.py", line 36, in parse_to_ast
    annotate_python_ast(py_ast, source_code, class_types, source_id, contract_name)
  File "/usr/local/lib/python3.8/dist-packages/vyper-0.2.8-py3.8.egg/vyper/ast/annotation.py", line 281, in annotate_python_ast
    tokens = asttokens.ASTTokens(source_code, tree=parsed_ast)
  File "/usr/local/lib/python3.8/dist-packages/asttokens-2.0.4-py3.8.egg/asttokens/asttokens.py", line 65, in __init__
    self.mark_tokens(self._tree)
  File "/usr/local/lib/python3.8/dist-packages/asttokens-2.0.4-py3.8.egg/asttokens/asttokens.py", line 76, in mark_tokens
    MarkTokens(self).visit_tree(root_node)
  File "/usr/local/lib/python3.8/dist-packages/asttokens-2.0.4-py3.8.egg/asttokens/mark_tokens.py", line 49, in visit_tree
    util.visit_tree(node, self._visit_before_children, self._visit_after_children)
  File "/usr/local/lib/python3.8/dist-packages/asttokens-2.0.4-py3.8.egg/asttokens/util.py", line 199, in visit_tree
    ret = postvisit(current, par_value, value)
  File "/usr/local/lib/python3.8/dist-packages/asttokens-2.0.4-py3.8.egg/asttokens/mark_tokens.py", line 92, in _visit_after_children
    nfirst, nlast = self._methods.get(self, node.__class__)(node, first, last)
  File "/usr/local/lib/python3.8/dist-packages/asttokens-2.0.4-py3.8.egg/asttokens/mark_tokens.py", line 189, in handle_attr
    name = self._code.next_token(dot)
  File "/usr/local/lib/python3.8/dist-packages/asttokens-2.0.4-py3.8.egg/asttokens/asttokens.py", line 141, in next_token
    while is_non_coding_token(self._tokens[i].type):
IndexError: list index out of range
agroce commented 3 years ago

(I did not get a chance to see if same exception chain, since the inputs are obviously different.

By the way, is it fine to submit bugs through just the string sent to 'vyper.compiler.compile_code'? Not going through vyper CLI is a huge win for persistent AFL fuzzing, but due to some file reading (with odd character) issues, they don't always reproduce. But I assume CompilerPanics or non-vyper exceptions from compile_code are fine, since under the hood CI is calling that, anyway?

agroce commented 3 years ago

(Attn @iamdefinitelyahuman on the fuzzing q)

agroce commented 3 years ago

I'll report mine separately, since for me the code in this bug report fails with:

root@c2bc5e4cc2af:~/vyfuzz# vyper v.vy 
ValueError: start (21,89) precedes previous end (22,0)

different symptom, while I can produce IndexError.

JhonnyJason commented 3 years ago

@agroce Very interesting the different Error Message :thinking:

Well I think the biggest problem for IndexError is that it is too general

agroce commented 3 years ago

Yeah, I think we probably just have different bugs, see https://github.com/vyperlang/vyper/issues/2258

charles-cooper commented 2 years ago

This was fixed in #2500