Skip to content

Commit

Permalink
Merge branch 'master' into perf/optimizer
Browse files Browse the repository at this point in the history
  • Loading branch information
charles-cooper authored May 21, 2024
2 parents 4d3dbaa + a0d9b1f commit 7fcd302
Show file tree
Hide file tree
Showing 61 changed files with 1,773 additions and 609 deletions.
125 changes: 51 additions & 74 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,97 +62,75 @@ jobs:

# "Regular"/core tests.
tests:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os || 'ubuntu' }}-latest
# IMPORTANT: Test defaults are duplicated in the "Run tests" step below!
# it is annoying that we need to duplicate them, but it is necessary
# to avoid repeating defaults for every "include" in the matrix.
name: "${{ matrix.os && matrix.os != 'ubuntu' && format('{0}-', matrix.os) || '' }}\
py${{ matrix.python-version[1] || '311' }}\
-opt-${{ matrix.opt-mode || 'gas' }}\
${{ matrix.debug && '-debug' || '' }}\
${{ matrix.experimental-codegen && '-experimental' || '' }}\
-${{ matrix.evm-version || 'cancun' }}\
-${{ matrix.evm-backend || 'revm' }}"
strategy:
matrix:
python-version: [["3.11", "311"]]
opt-mode: ["gas", "none", "codesize"]
# declare all variables used in the "include" section here! Conflicting jobs get overwritten by GitHub actions.
os: [ubuntu]
python-version: [["3.11", "311"]] # note: do not forget to replace 311 in the job names when upgrading!
opt-mode: [gas, none, codesize]
debug: [true, false]
evm-version: [shanghai]
evm-version: [cancun] # note: when upgrading, check the "include" section below for conflicting jobs
experimental-codegen: [false]
evm-backend: [revm]

# https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#expanding-or-adding-matrix-configurations
include:
# test default settings with 3.11 across all supported evm versions
- python-version: ["3.11", "311"]
debug: false
opt-mode: gas
evm-version: london
evm-backend: revm

- python-version: ["3.11", "311"]
debug: false
opt-mode: gas
evm-version: paris
evm-backend: revm
- evm-version: london
- evm-version: paris
- evm-version: shanghai

# test pre-cancun with opt-codesize and opt-none
- evm-version: shanghai
opt-mode: none
- evm-version: shanghai
opt-mode: codesize

# redundant rule, for clarity
- python-version: ["3.11", "311"]
debug: false
opt-mode: gas
# test py-evm
- evm-backend: py-evm
evm-version: shanghai
evm-backend: revm

- python-version: ["3.11", "311"]
debug: false
opt-mode: gas
- evm-backend: py-evm
evm-version: cancun
evm-backend: revm

# py-evm rules
- python-version: ["3.11", "311"]
debug: false
opt-mode: codesize
evm-version: london
evm-backend: py-evm

- python-version: ["3.11", "311"]
debug: false
opt-mode: gas
evm-version: cancun
evm-backend: py-evm

# test experimental pipeline
- python-version: ["3.11", "311"]
- experimental-codegen: true
opt-mode: gas
debug: false
evm-version: shanghai
evm-backend: revm
experimental-codegen: true
# TODO: test experimental_codegen + -Ocodesize
- experimental-codegen: true
opt-mode: none
- experimental-codegen: true
opt-mode: codesize

# run across other python versions. we don't really need to run all
# modes across all python versions - one is enough
- python-version: ["3.10", "310"]
opt-mode: gas
debug: false
evm-version: shanghai
evm-backend: revm

- python-version: ["3.12", "312"]
opt-mode: gas
debug: false
evm-version: shanghai
evm-backend: revm

name: "py${{ matrix.python-version[1] }}\
-opt-${{ matrix.opt-mode }}\
${{ matrix.debug && '-debug' || '' }}\
${{ matrix.experimental-codegen && '-experimental' || '' }}\
-${{ matrix.evm-version }}\
-${{ matrix.evm-backend }}"
# os-specific rules
- os: windows
- os: macos

steps:
- uses: actions/checkout@v4
with:
# need to fetch unshallow so that setuptools_scm can infer the version
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version[0] }}
- name: Set up Python ${{ matrix.python-version[0] || '3.11' }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version[0] }}
python-version: ${{ matrix.python-version[0] || '3.11' }}
cache: "pip"

- name: Install dependencies
Expand All @@ -162,32 +140,31 @@ jobs:
run: pip freeze

- name: Run tests
run: |
pytest \
-m "not fuzzing" \
--optimize ${{ matrix.opt-mode }} \
--evm-version ${{ matrix.evm-version }} \
${{ matrix.evm-backend && format('--evm-backend {0}', matrix.evm-backend) || '' }} \
${{ matrix.debug && '--enable-compiler-debug-mode' || '' }} \
${{ matrix.experimental-codegen && '--experimental-codegen' || '' }} \
--cov-branch \
--cov-report xml:coverage.xml \
--cov=vyper \
tests/
run: >
pytest
-m "not fuzzing"
--optimize ${{ matrix.opt-mode || 'gas' }}
--evm-version ${{ matrix.evm-version || 'cancun' }}
--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=vyper
tests/
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml


core-tests-success:
if: always()
# summary result from test matrix.
# see https://github.community/t/status-check-for-a-matrix-jobs/127354/7
runs-on: ubuntu-latest
needs: tests
needs: [tests]
steps:
- name: Check tests tests all succeeded
if: ${{ needs.tests.result != 'success' }}
Expand Down
10 changes: 5 additions & 5 deletions docs/compiling-a-contract.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,11 @@ When you compile your contract code, you can specify the target Ethereum Virtual
.. note::
If the evm version specified by the compiler options conflicts with the source code pragma, an exception will be raised and compilation will not continue.

For instance, the adding the following pragma to a contract indicates that it should be compiled for the "shanghai" fork of the EVM.
For instance, the adding the following pragma to a contract indicates that it should be compiled for the "cancun" fork of the EVM.

.. code-block:: vyper
#pragma evm-version shanghai
#pragma evm-version cancun
.. warning::

Expand Down Expand Up @@ -182,11 +182,11 @@ The following is a list of supported EVM versions, and changes in the compiler i
- ``block.difficulty`` is deprecated in favor of its new alias, ``block.prevrandao``.

.. py:attribute:: shanghai (default)
.. py:attribute:: shanghai
- The ``PUSH0`` opcode is automatically generated by the compiler instead of ``PUSH1 0``

.. py:attribute:: cancun (experimental)
.. py:attribute:: cancun (default)
- The ``transient`` keyword allows declaration of variables which live in transient storage
- Functions marked with ``@nonreentrant`` are protected with TLOAD/TSTORE instead of SLOAD/SSTORE
Expand Down Expand Up @@ -237,7 +237,7 @@ The following example describes the expected input format of ``vyper-json``. Com
},
// Optional
"settings": {
"evmVersion": "shanghai", // EVM version to compile for. Can be london, paris, shanghai (default) or cancun (experimental!).
"evmVersion": "cancun", // EVM version to compile for. Can be london, paris, shanghai or cancun (default).
// optional, optimization mode
// defaults to "gas". can be one of "gas", "codesize", "none",
// false and true (the last two are for backwards compatibility).
Expand Down
11 changes: 6 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def pytest_addoption(parser):
parser.addoption(
"--evm-version",
choices=list(evm_opcodes.EVM_VERSIONS.keys()),
default="shanghai",
default="cancun",
help="set evm version",
)

Expand All @@ -56,10 +56,11 @@ def pytest_addoption(parser):
@pytest.fixture(scope="module")
def output_formats():
output_formats = compiler.OUTPUT_FORMATS.copy()
del output_formats["bb"]
del output_formats["bb_runtime"]
del output_formats["cfg"]
del output_formats["cfg_runtime"]

to_drop = ("bb", "bb_runtime", "cfg", "cfg_runtime", "archive", "archive_b64", "solc_json")
for s in to_drop:
del output_formats[s]

return output_formats


Expand Down
39 changes: 39 additions & 0 deletions tests/functional/builtins/codegen/test_create_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,45 @@ def test(target: address):
assert test.foo() == 12


def test_blueprint_evals_once_side_effects(get_contract, deploy_blueprint_for, env):
# test msize allocator does not get trampled by salt= kwarg
code = """
foo: public(uint256)
"""

deployer_code = """
created_address: public(address)
deployed: public(uint256)
@external
def get() -> Bytes[32]:
self.deployed += 1
return b''
@external
def create_(target: address):
self.created_address = create_from_blueprint(
target,
raw_call(self, method_id("get()"), max_outsize=32),
raw_args=True, code_offset=3
)
"""

foo_contract = get_contract(code)
expected_runtime_code = env.get_code(foo_contract.address)

f, FooContract = deploy_blueprint_for(code)

d = get_contract(deployer_code)

d.create_(f.address)

test = FooContract(d.created_address())
assert env.get_code(test.address) == expected_runtime_code
assert test.foo() == 0
assert d.deployed() == 1


def test_create_copy_of_complex_kwargs(get_contract, env):
# test msize allocator does not get trampled by salt= kwarg
complex_salt = """
Expand Down
28 changes: 27 additions & 1 deletion tests/functional/builtins/codegen/test_slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def slice_tower_test(inp1: Bytes[50]) -> Bytes[50]:
def _fail_contract(code, opt_level, exceptions):
settings = Settings(optimize=opt_level)
with pytest.raises(exceptions):
compile_code(code, settings)
compile_code(code, settings=settings)


@pytest.mark.parametrize("use_literal_start", (True, False))
Expand Down Expand Up @@ -536,3 +536,29 @@ def test_slice_buffer_oob_reverts(bad_code, get_contract, tx_failed):
c = get_contract(bad_code)
with tx_failed():
c.do_slice()


# tests all 3 adhoc locations: `msg.data`, `self.code`, `<address>.code`
@pytest.mark.parametrize("adhoc_loc", ["msg.data", "self.code", "a.code"])
def test_slice_start_eval_once(get_contract, adhoc_loc):
code = f"""
counter: uint256
@internal
def bar() -> uint256:
self.counter += 1
return 1
@external
def foo(cs: String[64]) -> uint256:
s: Bytes[64] = b""
# use `a` to exercise the path with `<address>.code`
a: address = self
s = slice({adhoc_loc}, self.bar(), 3)
return self.counter
"""

arg = "a" * 64
c = get_contract(code)
# ensure that counter was incremented only once
assert c.foo(arg) == 1
Loading

0 comments on commit 7fcd302

Please sign in to comment.