vyperlang / titanoboa

a vyper interpreter
https://titanoboa.readthedocs.io
Other
247 stars 49 forks source link

Incorrect source map for errors raised in constructor #261

Closed DanielSchiavini closed 1 month ago

DanielSchiavini commented 1 month ago

When an exception is raised during the initcode, the source code map is incorrect. For example, take this code:

code = """
interface ChainlinkOracle:
    def latestRoundData() -> ChainlinkAnswer: view
    def decimals() -> uint8: view

struct ChainlinkAnswer:
    roundID: uint80
    answer: int256
    startedAt: uint256
    updatedAt: uint256
    answeredInRound: uint80

DECIMAL_MUL: immutable(uint256)
FEED: public(immutable(ChainlinkOracle))

@external
def __init__(feed: ChainlinkOracle):
    FEED = feed
    DECIMAL_MUL = 10**(18 - convert(feed.decimals(), uint256))

@external
@view
def rate() -> uint256:
    full_answer: ChainlinkAnswer = FEED.latestRoundData()
    return convert(full_answer.answer, uint256) * DECIMAL_MUL
"""
    boa.loads(code, "0x0000000000000000000000000000000000000000")

Will raise an exception with the wrong source:

E           boa.contracts.base_evm_contract.BoaError: Revert(b'')
E           
E           None
E            <compiler: bad calldatasize or callvalue>
E             contract "VyperContract:27", function "rate", line 27:35 
E                  26 def rate() -> uint256:
E             ---> 27     full_answer: ChainlinkAnswer = FEED.latestRoundData()
E             -------------------------------------------^
E                  28     return convert(full_answer.answer, uint256) * DECIMAL_MUL
E            <locals: full_answer=ChainlinkAnswer({'roundID': 0, 'answer': 826074471, 'startedAt': 0, 'updatedAt': 0, 'answeredInRound': 0})>

In fact, the error is caused by the following line:

    DECIMAL_MUL = 10**(18 - convert(feed.decimals(), uint256))
----------------------------------------^

See this uses the assembly_runtime which won't match: https://github.com/vyperlang/titanoboa/blob/32d9ae7d22ec1dc0e531c4af71ff795576162778/boa/contracts/vyper/vyper_contract.py#L644 find_source_of also has some is_initcode that is never used: https://github.com/vyperlang/titanoboa/blob/32d9ae7d22ec1dc0e531c4af71ff795576162778/boa/contracts/vyper/vyper_contract.py#L660

charles-cooper commented 1 month ago

wontfix, this is already handled in vyper-0.4.0 branch