Skip to content

Commit

Permalink
Merge branch 'master' into feat/improve-event-kwargs-recommendation
Browse files Browse the repository at this point in the history
  • Loading branch information
charles-cooper authored Jan 20, 2025
2 parents fd15d4b + 9a2cb2e commit 9c48102
Show file tree
Hide file tree
Showing 27 changed files with 1,414 additions and 101 deletions.
61 changes: 49 additions & 12 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,17 @@ jobs:
--evm-backend ${{ matrix.evm-backend || 'revm' }}
${{ matrix.debug && '--enable-compiler-debug-mode' || '' }}
${{ matrix.experimental-codegen && '--experimental-codegen' || '' }}
--cov-branch
--cov-report xml:coverage.xml
--cov-config=setup.cfg
--cov=vyper
tests/
- name: Upload Coverage
uses: codecov/codecov-action@v5
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
name: coverage-files-${{ github.job }}-${{ strategy.job-index }}
include-hidden-files: true
path: .coverage
if-no-files-found: error

core-tests-success:
if: always()
Expand Down Expand Up @@ -209,16 +210,17 @@ jobs:
--splits 120 \
--group ${{ matrix.group }} \
--splitting-algorithm least_duration \
--cov-branch \
--cov-report xml:coverage.xml \
--cov-config=setup.cfg \
--cov=vyper \
tests/
- name: Upload Coverage
uses: codecov/codecov-action@v5
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
name: coverage-files-${{ github.job }}-${{ strategy.job-index }}
include-hidden-files: true
path: .coverage
if-no-files-found: error

slow-tests-success:
if: always()
Expand All @@ -231,3 +233,38 @@ jobs:
- name: Check slow tests all succeeded
if: ${{ needs.fuzzing.result != 'success' }}
run: exit 1

consolidate-coverage:
# Consolidate code coverage using `coverage combine` and upload
# to the codecov app
runs-on: ubuntu-latest
needs: [tests, fuzzing]

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: "pip"

- name: Install coverage
run: pip install coverage

- name: Download coverage artifacts
uses: actions/download-artifact@v4
with:
pattern: coverage-files-*
path: coverage-files

- name: Combine coverage
run: |
coverage combine coverage-files/**/.coverage
coverage xml
- name: Upload Coverage
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: coverage.xml
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ be a bit behind the latest version found in the master branch of this repository

```bash
make dev-init
python setup.py test
./quicktest.sh -m "not fuzzing"
```

## Developing (working on the compiler)
Expand Down
11 changes: 10 additions & 1 deletion quicktest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@

# examples:
# ./quicktest.sh
# ./quicktest.sh -m "not fuzzing"
# ./quicktest.sh -m "not fuzzing" -n<cpu cores - 2> (this is the most useful)
# ./quicktest.sh -m "not fuzzing" -n0
# ./quicktest.sh tests/.../mytest.py

# run pytest but bail out on first error
# useful for dev workflow
# useful for dev workflow.

pytest -q -s --instafail -x --disable-warnings "$@"

# useful options include:
# -n0 (uses only one core but faster startup)
# -nauto (uses only one core but faster startup)
# -m "not fuzzing" - skip slow/fuzzing tests
12 changes: 12 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,15 @@ markers =
fuzzing: Run Hypothesis fuzz test suite (deselect with '-m "not fuzzing"')
requires_evm_version(version): Mark tests that require at least a specific EVM version and would throw `EvmVersionException` otherwise
venom_xfail: mark a test case as a regression (expected to fail) under the venom pipeline


[coverage:run]
branch = True
source = vyper

# this is not available on the CI step that performs `coverage combine`
omit = vyper/version.py

# allow `coverage combine` to combine reports from heterogeneous OSes.
# (mainly important for consolidating coverage reports in the CI).
relative_files = True
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ def _global_version(version):
"importlib-metadata",
"wheel",
],
setup_requires=["pytest-runner", "setuptools_scm>=7.1.0,<8.0.0"],
tests_require=extras_require["test"],
setup_requires=["setuptools_scm>=7.1.0,<8.0.0"],
extras_require=extras_require,
entry_points={
"console_scripts": [
Expand Down
42 changes: 41 additions & 1 deletion tests/functional/builtins/codegen/test_ecrecover.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import contextlib

from eth_account import Account
from eth_account._utils.signing import to_bytes32

from tests.utils import ZERO_ADDRESS
from tests.utils import ZERO_ADDRESS, check_precompile_asserts
from vyper.compiler.settings import OptimizationLevel


def test_ecrecover_test(get_contract):
Expand Down Expand Up @@ -86,3 +89,40 @@ def test_ecrecover() -> bool:
"""
c = get_contract(code)
assert c.test_ecrecover() is True


def test_ecrecover_oog_handling(env, get_contract, tx_failed, optimize, experimental_codegen):
# GHSA-vgf2-gvx8-xwc3
code = """
@external
@view
def do_ecrecover(hash: bytes32, v: uint256, r:uint256, s:uint256) -> address:
return ecrecover(hash, v, r, s)
"""
check_precompile_asserts(code)

c = get_contract(code)

h = b"\x35" * 32
local_account = Account.from_key(b"\x46" * 32)
sig = local_account.signHash(h)
v, r, s = sig.v, sig.r, sig.s

assert c.do_ecrecover(h, v, r, s) == local_account.address

gas_used = env.last_result.gas_used

if optimize == OptimizationLevel.NONE and not experimental_codegen:
# if optimizations are off, enough gas is used by the contract
# that the gas provided to ecrecover (63/64ths rule) is enough
# for it to succeed
ctx = contextlib.nullcontext
else:
# in other cases, the gas forwarded is small enough for ecrecover
# to fail with oog, which we handle by reverting.
ctx = tx_failed

with ctx():
# provide enough spare gas for the top-level call to not oog but
# not enough for ecrecover to succeed
c.do_ecrecover(h, v, r, s, gas=gas_used)
19 changes: 15 additions & 4 deletions tests/functional/builtins/codegen/test_slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
from vyper.compiler import compile_code
from vyper.compiler.settings import OptimizationLevel, Settings
from vyper.evm.opcodes import version_check
from vyper.exceptions import ArgumentException, CompilerPanic, TypeMismatch
from vyper.exceptions import (
ArgumentException,
CompilerPanic,
StaticAssertionException,
TypeMismatch,
)

_fun_bytes32_bounds = [(0, 32), (3, 29), (27, 5), (0, 5), (5, 3), (30, 2)]

Expand Down Expand Up @@ -533,9 +538,15 @@ def do_slice():

@pytest.mark.parametrize("bad_code", oob_fail_list)
def test_slice_buffer_oob_reverts(bad_code, get_contract, tx_failed):
c = get_contract(bad_code)
with tx_failed():
c.do_slice()
try:
c = get_contract(bad_code)
with tx_failed():
c.do_slice()
except StaticAssertionException:
# it should be ok if we
# catch the assert in compile time
# since it supposed to be revert
pass


# tests all 3 adhoc locations: `msg.data`, `self.code`, `<address>.code`
Expand Down
2 changes: 0 additions & 2 deletions tests/functional/codegen/features/test_clampers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from eth_utils import keccak

from tests.utils import ZERO_ADDRESS, decimal_to_int
from vyper.exceptions import StackTooDeep
from vyper.utils import int_bounds


Expand Down Expand Up @@ -502,7 +501,6 @@ def foo(b: DynArray[int128, 10]) -> DynArray[int128, 10]:


@pytest.mark.parametrize("value", [0, 1, -1, 2**127 - 1, -(2**127)])
@pytest.mark.venom_xfail(raises=StackTooDeep, reason="stack scheduler regression")
def test_multidimension_dynarray_clamper_passing(get_contract, value):
code = """
@external
Expand Down
74 changes: 70 additions & 4 deletions tests/functional/codegen/types/test_dynamic_array.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import contextlib
import itertools
from typing import Any, Callable

import pytest

from tests.utils import decimal_to_int
from tests.utils import check_precompile_asserts, decimal_to_int
from vyper.compiler import compile_code
from vyper.evm.opcodes import version_check
from vyper.exceptions import (
ArgumentException,
ArrayIndexException,
CompilerPanic,
ImmutableViolation,
OverflowException,
StateAccessViolation,
StaticAssertionException,
TypeMismatch,
)

Expand Down Expand Up @@ -1861,9 +1864,16 @@ def should_revert() -> DynArray[String[65], 2]:
@pytest.mark.parametrize("code", dynarray_length_no_clobber_cases)
def test_dynarray_length_no_clobber(get_contract, tx_failed, code):
# check that length is not clobbered before dynarray data copy happens
c = get_contract(code)
with tx_failed():
c.should_revert()
try:
c = get_contract(code)
with tx_failed():
c.should_revert()
except StaticAssertionException:
# this test should create
# assert error so if it is
# detected in compile time
# we can continue
pass


def test_dynarray_make_setter_overlap(get_contract):
Expand Down Expand Up @@ -1901,3 +1911,59 @@ def foo():
c = get_contract(code)
with tx_failed():
c.foo()


def test_dynarray_copy_oog(env, get_contract, tx_failed):
# GHSA-vgf2-gvx8-xwc3
code = """
@external
def foo(a: DynArray[uint256, 4000]) -> uint256:
b: DynArray[uint256, 4000] = a
return b[0]
"""
check_precompile_asserts(code)

c = get_contract(code)
dynarray = [2] * 4000
assert c.foo(dynarray) == 2

gas_used = env.last_result.gas_used
if version_check(begin="cancun"):
ctx = contextlib.nullcontext
else:
ctx = tx_failed

with ctx():
# depends on EVM version. pre-cancun, will revert due to checking
# success flag from identity precompile.
c.foo(dynarray, gas=gas_used)


def test_dynarray_copy_oog2(env, get_contract, tx_failed):
# GHSA-vgf2-gvx8-xwc3
code = """
@external
@view
def foo(x: String[1000000], y: String[1000000]) -> DynArray[String[1000000], 2]:
z: DynArray[String[1000000], 2] = [x, y]
# Some code
return z
"""
check_precompile_asserts(code)

c = get_contract(code)
calldata0 = "a" * 10
calldata1 = "b" * 1000000
assert c.foo(calldata0, calldata1) == [calldata0, calldata1]

gas_used = env.last_result.gas_used
if version_check(begin="cancun"):
ctx = contextlib.nullcontext
else:
ctx = tx_failed

with ctx():
# depends on EVM version. pre-cancun, will revert due to checking
# success flag from identity precompile.
c.foo(calldata0, calldata1, gas=gas_used)
Loading

0 comments on commit 9c48102

Please sign in to comment.