Skip to content

Commit

Permalink
Merge branch 'master' into feat/improve-volatile
Browse files Browse the repository at this point in the history
  • Loading branch information
charles-cooper authored Jan 20, 2025
2 parents 8d93190 + 4d693b7 commit d99d9ad
Show file tree
Hide file tree
Showing 41 changed files with 1,778 additions and 275 deletions.
13 changes: 7 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ jobs:
- name: Upload Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: vyper-${{ runner.os }}
path: dist/vyper.*

windows-build:
Expand Down Expand Up @@ -81,8 +82,9 @@ jobs:
./make.cmd freeze
- name: Upload Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: vyper-${{ runner.os }}
path: dist/vyper.*

publish-release-assets:
Expand All @@ -92,14 +94,13 @@ jobs:

steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
path: artifacts/
merge-multiple: true

- name: Upload assets
# fun - artifacts are downloaded into "artifact/".
# TODO: this needs to be tested when upgrading to upload-artifact v4
working-directory: artifacts/artifact
working-directory: artifacts
run: |
set -Eeuxo pipefail
for BIN_NAME in $(ls)
Expand Down
96 changes: 84 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,73 @@ jobs:
- name: Check slow tests all succeeded
if: ${{ needs.fuzzing.result != 'success' }}
run: exit 1

coverage-report:
# Consolidate code coverage using `coverage combine` and
# call coverage report with fail-under=90
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
- name: Coverage report
# coverage report and fail if coverage is too low
run: |
coverage report --fail-under=90
- name: Generate coverage.xml
run: |
coverage xml
- name: Upload coverage sqlite artifact
# upload coverage sqlite db for debugging
uses: actions/upload-artifact@v4
with:
name: coverage-sqlite
include-hidden-files: true
path: .coverage
if-no-files-found: error

- name: Upload coverage.xml
uses: actions/upload-artifact@v4
with:
name: coverage-xml
path: coverage.xml
if-no-files-found: error

upload-coverage:
# upload coverage to the codecov app
runs-on: ubuntu-latest
needs: [coverage-report]

steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: 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
25 changes: 25 additions & 0 deletions tests/ast_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from vyper.ast.nodes import VyperNode


def deepequals(node: VyperNode, other: VyperNode):
# checks two nodes are recursively equal, ignoring metadata
# like line info.
if not isinstance(other, type(node)):
return False

if isinstance(node, list):
if len(node) != len(other):
return False
return all(deepequals(a, b) for a, b in zip(node, other))

if not isinstance(node, VyperNode):
return node == other

if getattr(node, "node_id", None) != getattr(other, "node_id", None):
return False
for field_name in (i for i in node.get_fields() if i not in VyperNode.__slots__):
lhs = getattr(node, field_name, None)
rhs = getattr(other, field_name, None)
if not deepequals(lhs, rhs):
return False
return True
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
Loading

0 comments on commit d99d9ad

Please sign in to comment.