Skip to content

Commit

Permalink
Merge branch 'master' into fix/extcall_range
Browse files Browse the repository at this point in the history
  • Loading branch information
charles-cooper authored Feb 24, 2025
2 parents cbd916b + dd5a3d9 commit fc76404
Show file tree
Hide file tree
Showing 54 changed files with 1,205 additions and 223 deletions.
2 changes: 1 addition & 1 deletion docs/built-in-functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ Math
.. py:function:: sqrt(d: decimal) -> decimal
Return the square root of the provided decimal number, using the Babylonian square root algorithm.
Return the square root of the provided decimal number, using the Babylonian square root algorithm. The rounding mode is to round down to the nearest epsilon. For instance, ``sqrt(0.9999999998) == 0.9999999998``.

.. code-block:: vyper
Expand Down
17 changes: 17 additions & 0 deletions docs/compiling-a-contract.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@ The following is a list of supported EVM versions, and changes in the compiler i
- Functions marked with ``@nonreentrant`` are protected with TLOAD/TSTORE instead of SLOAD/SSTORE
- The ``MCOPY`` opcode will be generated automatically by the compiler for most memory operations.


.. _warnings:

Controlling Warnings
====================

Vyper allows suppression of warnings via the CLI flag ``-Wnone``, or promotion of (all) warnings to errors via the ``-Werror`` flag.

.. code:: shell
$ vyper -Wnone foo.vy # suppress warnings
.. code:: shell
$ vyper -Werror foo.vy # promote warnings to errors
.. _integrity-hash:

Integrity Hash
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""
Test functionality of internal functions which may be inlined
"""
# note for refactor: this may be able to be merged with
# calling_convention/test_internal_call.py


def test_call_in_call(get_contract):
code = """
@internal
def _foo(a: uint256,) -> uint256:
return 1 + a
@internal
def _foo2() -> uint256:
return 4
@external
def foo() -> uint256:
return self._foo(self._foo2())
"""

c = get_contract(code)
assert c.foo() == 5


def test_call_in_call_with_raise(get_contract, tx_failed):
code = """
@internal
def sum(a: uint256) -> uint256:
if a > 1:
return a + 1
raise
@internal
def middle(a: uint256) -> uint256:
return self.sum(a)
@external
def test(a: uint256) -> uint256:
return self.middle(a)
"""

c = get_contract(code)

assert c.test(2) == 3

with tx_failed():
c.test(0)


def test_inliner_with_unused_param(get_contract):
code = """
data: public(uint256)
@internal
def _foo(start: uint256, length: uint256):
self.data = start
@external
def foo(x: uint256, y: uint256):
self._foo(x, y)
"""

c = get_contract(code)
c.foo(1, 2)
64 changes: 64 additions & 0 deletions tests/functional/codegen/features/iteration/test_for_in_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -945,3 +945,67 @@ def foo() -> DynArray[uint256, 12]:
"""
c = get_contract(code)
assert c.foo() == [1, 2, 3]


def test_iterator_eval_order(get_contract):
# GHSA-h33q-mhmp-8p67
code = """
x: uint256
trace: DynArray[uint256, 3]
@deploy
def __init__():
self.x = 0
@external
def test():
for i: uint256 in [self.usesideeffect(), self.usesideeffect(), self.usesideeffect()]:
self.x += 1
self.trace.append(i)
@view
def usesideeffect() -> uint256:
return self.x
@view
@external
def get_trace() -> DynArray[uint256, 3]:
return self.trace
"""
c = get_contract(code)
c.test()
assert c.get_trace() == [0, 0, 0]


def test_iterator_eval_order2(get_contract):
# GHSA-h33q-mhmp-8p67
code = """
x: uint256
trace: DynArray[uint256, 3]
@deploy
def __init__():
self.x = 0
@external
def test():
for i: uint256 in ([self.usesideeffect(), self.usesideeffect(), self.usesideeffect()] if True else self.otherclause()):
self.x += 1
self.trace.append(i)
@view
def usesideeffect() -> uint256:
return self.x
@view
def otherclause() -> uint256[3]:
return [0, 0, 0]
@view
@external
def get_trace() -> DynArray[uint256, 3]:
return self.trace
""" # noqa: E501
c = get_contract(code)
c.test()
assert c.get_trace() == [0, 0, 0]
131 changes: 130 additions & 1 deletion tests/functional/codegen/features/test_assignment.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from vyper.exceptions import ImmutableViolation, InvalidType, TypeMismatch
from vyper.exceptions import CodegenPanic, ImmutableViolation, InvalidType, TypeMismatch


def test_augassign(get_contract):
Expand Down Expand Up @@ -39,6 +39,135 @@ def augmod(x: int128, y: int128) -> int128:
print("Passed aug-assignment test")


@pytest.mark.parametrize(
"source",
[
"""
@external
def poc():
a: DynArray[uint256, 2] = [1, 2]
a[1] += a.pop()
""",
"""
a: DynArray[uint256, 2]
def side_effect() -> uint256:
return self.a.pop()
@external
def poc():
self.a = [1, 2]
self.a[1] += self.side_effect()
""",
"""
a: DynArray[uint256, 2]
def side_effect() -> uint256:
self.a = [1]
return 1
@external
def poc():
self.a = [1, 2]
self.a[1] += self.side_effect()
""",
"""
a: DynArray[uint256, 2]
interface Foo:
def foo() -> uint256: nonpayable
@external
def foo() -> uint256:
return self.a.pop()
@external
def poc():
self.a = [1, 2]
# panics due to extcall
self.a[1] += extcall Foo(self).foo()
""",
],
)
@pytest.mark.xfail(strict=True, raises=CodegenPanic)
def test_augassign_oob(get_contract, tx_failed, source):
# xfail here (with panic):
c = get_contract(source)

# not reached until the panic is fixed
with tx_failed(c):
c.poc()


@pytest.mark.parametrize(
"source",
[
"""
a: public(DynArray[uint256, 2])
interface Foo:
def foo() -> uint256: view
@external
def foo() -> uint256:
return self.a[1]
@external
def entry() -> DynArray[uint256, 2]:
self.a = [1, 1]
# panics due to staticcall
self.a[1] += staticcall Foo(self).foo()
return self.a
"""
],
)
@pytest.mark.xfail(strict=True, raises=CodegenPanic)
def test_augassign_rhs_references_lhs(get_contract, tx_failed, source):
# xfail here (with panic):
c = get_contract(source)

assert c.entry() == [1, 2]


@pytest.mark.parametrize(
"source",
[
"""
@external
def entry() -> DynArray[uint256, 2]:
a: DynArray[uint256, 2] = [1, 1]
a[1] += a[1]
return a
""",
"""
@external
def entry() -> DynArray[uint256, 2]:
a: uint256 = 1
a += a
b: DynArray[uint256, 2] = [a, a]
b[0] -= b[0]
b[0] += b[1] // 2
return b
""",
"""
a: DynArray[uint256, 2]
def read() -> uint256:
return self.a[1]
@external
def entry() -> DynArray[uint256, 2]:
self.a = [1, 1]
self.a[1] += self.read()
return self.a
""",
],
)
def test_augassign_rhs_references_lhs2(get_contract, source):
c = get_contract(source)
assert c.entry() == [1, 2]


@pytest.mark.parametrize(
"typ,in_val,out_val",
[
Expand Down
4 changes: 4 additions & 0 deletions tests/functional/codegen/types/numbers/test_sqrt.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ def test_sqrt_bounds(sqrt_contract, value):
)
@hypothesis.example(value=Decimal(SizeLimits.MAX_INT128))
@hypothesis.example(value=Decimal(0))
# cf. GHSA-2p94-8669-xg86 for the following three examples:
@hypothesis.example(value=Decimal("0.9999999998"))
@hypothesis.example(value=Decimal("0.9999999997"))
@hypothesis.example(value=Decimal("1.1000000000"))
def test_sqrt_valid_range(sqrt_contract, value):
vyper_sqrt = sqrt_contract.test(decimal_to_int(value))
actual_sqrt = decimal_sqrt(value)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import random

import pytest

import vyper


@pytest.fixture
def huge_bytestring():
r = random.Random(b"vyper")

return bytes([r.getrandbits(8) for _ in range(0x6001)])


def test_contract_size_exceeded(huge_bytestring):
code = f"""
@external
def a() -> bool:
q: Bytes[24577] = {huge_bytestring}
return True
"""
with pytest.warns(vyper.warnings.ContractSizeLimit):
vyper.compile_code(code, output_formats=["bytecode_runtime"])
50 changes: 50 additions & 0 deletions tests/functional/syntax/warnings/test_deprecation_warning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import json

import pytest

import vyper
from vyper.cli.vyper_json import compile_json

deprecated = [
"""
struct Foo:
a: uint256
b: uint256
@external
def foo():
f: Foo = Foo({a: 128, b: 256})
""",
"""
event Foo:
a: uint256
b: uint256
@external
def foo():
log Foo({a: 128, b: 256})
""",
]


@pytest.mark.parametrize("code", deprecated)
def test_deprecated_warning(code):
with pytest.warns(vyper.warnings.Deprecation):
vyper.compile_code(code)


def test_deprecated_optimize_boolean_flag():
code = """
@external
def foo():
pass
"""

input_json = {
"language": "Vyper",
"sources": {"contracts/foo.vy": {"content": code}},
"settings": {"outputSelection": {"*": ["*"]}, "optimize": True},
}

with pytest.warns(vyper.warnings.Deprecation):
compile_json(json.dumps(input_json))
Loading

0 comments on commit fc76404

Please sign in to comment.