Skip to content

Commit

Permalink
Merge branch 'master' into refactor/single_exit
Browse files Browse the repository at this point in the history
  • Loading branch information
charles-cooper committed Jan 14, 2024
2 parents 7b2c74b + 3f013ec commit 8fecd11
Show file tree
Hide file tree
Showing 88 changed files with 1,286 additions and 930 deletions.
1 change: 1 addition & 0 deletions docs/resources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Frameworks and tooling
- `🐍 snekmate – Vyper smart contract building blocks <https://github.com/pcaversaccio/snekmate>`_
- `Serpentor – A set of smart contracts tools for governance <https://github.com/yearn/serpentor>`_
- `Smart contract development frameworks and tools for Vyper on Ethreum.org <https://ethereum.org/en/developers/docs/programming-languages/python/>`_
- `Vyper Online Compiler - an online platform for compiling and deploying Vyper smart contracts <https://github.com/0x0077/vyper-online-compiler>`_

Security
--------
Expand Down
2 changes: 1 addition & 1 deletion examples/auctions/blind_auction.vy
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def reveal(_numBids: int128, _values: uint256[128], _fakes: bool[128], _secrets:

# Calculate refund for sender
refund: uint256 = 0
for i in range(MAX_BIDS):
for i: int128 in range(MAX_BIDS):
# Note that loop may break sooner than 128 iterations if i >= _numBids
if (i >= _numBids):
break
Expand Down
8 changes: 4 additions & 4 deletions examples/tokens/ERC1155ownable.vy
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def balanceOfBatch(accounts: DynArray[address, BATCH_SIZE], ids: DynArray[uint25
assert len(accounts) == len(ids), "ERC1155: accounts and ids length mismatch"
batchBalances: DynArray[uint256, BATCH_SIZE] = []
j: uint256 = 0
for i in ids:
for i: uint256 in ids:
batchBalances.append(self.balanceOf[accounts[j]][i])
j += 1
return batchBalances
Expand Down Expand Up @@ -243,7 +243,7 @@ def mintBatch(receiver: address, ids: DynArray[uint256, BATCH_SIZE], amounts: Dy
assert len(ids) == len(amounts), "ERC1155: ids and amounts length mismatch"
operator: address = msg.sender

for i in range(BATCH_SIZE):
for i: uint256 in range(BATCH_SIZE):
if i >= len(ids):
break
self.balanceOf[receiver][ids[i]] += amounts[i]
Expand Down Expand Up @@ -277,7 +277,7 @@ def burnBatch(ids: DynArray[uint256, BATCH_SIZE], amounts: DynArray[uint256, BAT
assert len(ids) == len(amounts), "ERC1155: ids and amounts length mismatch"
operator: address = msg.sender

for i in range(BATCH_SIZE):
for i: uint256 in range(BATCH_SIZE):
if i >= len(ids):
break
self.balanceOf[msg.sender][ids[i]] -= amounts[i]
Expand Down Expand Up @@ -333,7 +333,7 @@ def safeBatchTransferFrom(sender: address, receiver: address, ids: DynArray[uint
assert sender == msg.sender or self.isApprovedForAll[sender][msg.sender], "Caller is neither owner nor approved operator for this ID"
assert len(ids) == len(amounts), "ERC1155: ids and amounts length mismatch"
operator: address = msg.sender
for i in range(BATCH_SIZE):
for i: uint256 in range(BATCH_SIZE):
if i >= len(ids):
break
id: uint256 = ids[i]
Expand Down
6 changes: 3 additions & 3 deletions examples/voting/ballot.vy
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def directlyVoted(addr: address) -> bool:
def __init__(_proposalNames: bytes32[2]):
self.chairperson = msg.sender
self.voterCount = 0
for i in range(2):
for i: int128 in range(2):
self.proposals[i] = Proposal({
name: _proposalNames[i],
voteCount: 0
Expand Down Expand Up @@ -82,7 +82,7 @@ def _forwardWeight(delegate_with_weight_to_forward: address):
assert self.voters[delegate_with_weight_to_forward].weight > 0

target: address = self.voters[delegate_with_weight_to_forward].delegate
for i in range(4):
for i: int128 in range(4):
if self._delegated(target):
target = self.voters[target].delegate
# The following effectively detects cycles of length <= 5,
Expand Down Expand Up @@ -157,7 +157,7 @@ def vote(proposal: int128):
def _winningProposal() -> int128:
winning_vote_count: int128 = 0
winning_proposal: int128 = 0
for i in range(2):
for i: int128 in range(2):
if self.proposals[i].voteCount > winning_vote_count:
winning_vote_count = self.proposals[i].voteCount
winning_proposal = i
Expand Down
4 changes: 2 additions & 2 deletions examples/wallet/wallet.vy
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ seq: public(int128)

@external
def __init__(_owners: address[5], _threshold: int128):
for i in range(5):
for i: uint256 in range(5):
if _owners[i] != empty(address):
self.owners[i] = _owners[i]
self.threshold = _threshold
Expand Down Expand Up @@ -47,7 +47,7 @@ def approve(_seq: int128, to: address, _value: uint256, data: Bytes[4096], sigda
assert self.seq == _seq
# # Iterates through all the owners and verifies that there signatures,
# # given as the sigdata argument are correct
for i in range(5):
for i: uint256 in range(5):
if sigdata[i][0] != 0:
# If an invalid signature is given for an owner then the contract throws
assert ecrecover(h2, sigdata[i][0], sigdata[i][1], sigdata[i][2]) == self.owners[i]
Expand Down
43 changes: 29 additions & 14 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ def pytest_addoption(parser):
parser.addoption("--enable-compiler-debug-mode", action="store_true")


@pytest.fixture(scope="module")
def output_formats():
output_formats = compiler.OUTPUT_FORMATS.copy()
del output_formats["bb"]
del output_formats["bb_runtime"]
return output_formats


@pytest.fixture(scope="module")
def optimize(pytestconfig):
flag = pytestconfig.getoption("optimize")
Expand Down Expand Up @@ -281,15 +289,22 @@ def ir_compiler(ir, *args, **kwargs):


def _get_contract(
w3, source_code, optimize, *args, override_opt_level=None, input_bundle=None, **kwargs
w3,
source_code,
optimize,
output_formats,
*args,
override_opt_level=None,
input_bundle=None,
**kwargs,
):
settings = Settings()
settings.evm_version = kwargs.pop("evm_version", None)
settings.optimize = override_opt_level or optimize
out = compiler.compile_code(
source_code,
# test that all output formats can get generated
output_formats=list(compiler.OUTPUT_FORMATS.keys()),
output_formats=output_formats,
settings=settings,
input_bundle=input_bundle,
show_gas_estimates=True, # Enable gas estimates for testing
Expand All @@ -309,17 +324,17 @@ def _get_contract(


@pytest.fixture(scope="module")
def get_contract(w3, optimize):
def get_contract(w3, optimize, output_formats):
def fn(source_code, *args, **kwargs):
return _get_contract(w3, source_code, optimize, *args, **kwargs)
return _get_contract(w3, source_code, optimize, output_formats, *args, **kwargs)

return fn


@pytest.fixture
def get_contract_with_gas_estimation(tester, w3, optimize):
def get_contract_with_gas_estimation(tester, w3, optimize, output_formats):
def get_contract_with_gas_estimation(source_code, *args, **kwargs):
contract = _get_contract(w3, source_code, optimize, *args, **kwargs)
contract = _get_contract(w3, source_code, optimize, output_formats, *args, **kwargs)
for abi_ in contract._classic_contract.functions.abi:
if abi_["type"] == "function":
set_decorator_to_contract_function(w3, tester, contract, source_code, abi_["name"])
Expand All @@ -329,15 +344,15 @@ def get_contract_with_gas_estimation(source_code, *args, **kwargs):


@pytest.fixture
def get_contract_with_gas_estimation_for_constants(w3, optimize):
def get_contract_with_gas_estimation_for_constants(w3, optimize, output_formats):
def get_contract_with_gas_estimation_for_constants(source_code, *args, **kwargs):
return _get_contract(w3, source_code, optimize, *args, **kwargs)
return _get_contract(w3, source_code, optimize, output_formats, *args, **kwargs)

return get_contract_with_gas_estimation_for_constants


@pytest.fixture(scope="module")
def get_contract_module(optimize):
def get_contract_module(optimize, output_formats):
"""
This fixture is used for Hypothesis tests to ensure that
the same contract is called over multiple runs of the test.
Expand All @@ -350,18 +365,18 @@ def get_contract_module(optimize):
w3.eth.set_gas_price_strategy(zero_gas_price_strategy)

def get_contract_module(source_code, *args, **kwargs):
return _get_contract(w3, source_code, optimize, *args, **kwargs)
return _get_contract(w3, source_code, optimize, output_formats, *args, **kwargs)

return get_contract_module


def _deploy_blueprint_for(w3, source_code, optimize, initcode_prefix=b"", **kwargs):
def _deploy_blueprint_for(w3, source_code, optimize, output_formats, initcode_prefix=b"", **kwargs):
settings = Settings()
settings.evm_version = kwargs.pop("evm_version", None)
settings.optimize = optimize
out = compiler.compile_code(
source_code,
output_formats=list(compiler.OUTPUT_FORMATS.keys()),
output_formats=output_formats,
settings=settings,
show_gas_estimates=True, # Enable gas estimates for testing
)
Expand Down Expand Up @@ -394,9 +409,9 @@ def factory(address):


@pytest.fixture(scope="module")
def deploy_blueprint_for(w3, optimize):
def deploy_blueprint_for(w3, optimize, output_formats):
def deploy_blueprint_for(source_code, *args, **kwargs):
return _deploy_blueprint_for(w3, source_code, optimize, *args, **kwargs)
return _deploy_blueprint_for(w3, source_code, optimize, output_formats, *args, **kwargs)

return deploy_blueprint_for

Expand Down
4 changes: 2 additions & 2 deletions tests/functional/builtins/codegen/test_empty.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ def test_empty(xs: int128[111], ys: Bytes[1024], zs: Bytes[31]) -> bool: view
@internal
def write_junk_to_memory():
xs: int128[1024] = empty(int128[1024])
for i in range(1024):
for i: uint256 in range(1024):
xs[i] = -(i + 1)
@internal
def priv(xs: int128[111], ys: Bytes[1024], zs: Bytes[31]) -> bool:
Expand Down Expand Up @@ -469,7 +469,7 @@ def test_return_empty(get_contract_with_gas_estimation):
@internal
def write_junk_to_memory():
xs: int128[1024] = empty(int128[1024])
for i in range(1024):
for i: uint256 in range(1024):
xs[i] = -(i + 1)
@external
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/builtins/codegen/test_mulmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_uint256_mulmod_complex(get_contract_with_gas_estimation):
@external
def exponential(base: uint256, exponent: uint256, modulus: uint256) -> uint256:
o: uint256 = 1
for i in range(256):
for i: uint256 in range(256):
o = uint256_mulmod(o, o, modulus)
if exponent & shift(1, 255 - i) != 0:
o = uint256_mulmod(o, base, modulus)
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/builtins/codegen/test_slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_basic_slice(get_contract_with_gas_estimation):
@external
def slice_tower_test(inp1: Bytes[50]) -> Bytes[50]:
inp: Bytes[50] = inp1
for i in range(1, 11):
for i: uint256 in range(1, 11):
inp = slice(inp, 1, 30 - i * 2)
return inp
"""
Expand Down
7 changes: 3 additions & 4 deletions tests/functional/builtins/folding/test_abs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from hypothesis import example, given, settings
from hypothesis import strategies as st

from vyper import ast as vy_ast
from vyper.builtins import functions as vy_fn
from tests.utils import parse_and_fold
from vyper.exceptions import InvalidType


Expand All @@ -19,9 +18,9 @@ def foo(a: int256) -> int256:
"""
contract = get_contract(source)

vyper_ast = vy_ast.parse_to_ast(f"abs({a})")
vyper_ast = parse_and_fold(f"abs({a})")
old_node = vyper_ast.body[0].value
new_node = vy_fn.DISPATCH_TABLE["abs"]._try_fold(old_node)
new_node = old_node.get_folded_value()

assert contract.foo(a) == new_node.value == abs(a)

Expand Down
7 changes: 3 additions & 4 deletions tests/functional/builtins/folding/test_addmod_mulmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from hypothesis import assume, given, settings
from hypothesis import strategies as st

from vyper import ast as vy_ast
from vyper.builtins import functions as vy_fn
from tests.utils import parse_and_fold

st_uint256 = st.integers(min_value=0, max_value=2**256 - 1)

Expand All @@ -22,8 +21,8 @@ def foo(a: uint256, b: uint256, c: uint256) -> uint256:
"""
contract = get_contract(source)

vyper_ast = vy_ast.parse_to_ast(f"{fn_name}({a}, {b}, {c})")
vyper_ast = parse_and_fold(f"{fn_name}({a}, {b}, {c})")
old_node = vyper_ast.body[0].value
new_node = vy_fn.DISPATCH_TABLE[fn_name]._try_fold(old_node)
new_node = old_node.get_folded_value()

assert contract.foo(a, b, c) == new_node.value
16 changes: 7 additions & 9 deletions tests/functional/builtins/folding/test_bitwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from hypothesis import given, settings
from hypothesis import strategies as st

from vyper import ast as vy_ast
from tests.utils import parse_and_fold
from vyper.exceptions import InvalidType, OverflowException
from vyper.semantics.analysis.utils import validate_expected_type
from vyper.semantics.types.shortcuts import INT256_T, UINT256_T
Expand All @@ -29,7 +29,7 @@ def foo(a: uint256, b: uint256) -> uint256:

contract = get_contract(source)

vyper_ast = vy_ast.parse_to_ast(f"{a} {op} {b}")
vyper_ast = parse_and_fold(f"{a} {op} {b}")
old_node = vyper_ast.body[0].value
new_node = old_node.get_folded_value()

Expand All @@ -48,10 +48,9 @@ def foo(a: uint256, b: uint256) -> uint256:
"""
contract = get_contract(source)

vyper_ast = vy_ast.parse_to_ast(f"{a} {op} {b}")
old_node = vyper_ast.body[0].value

try:
vyper_ast = parse_and_fold(f"{a} {op} {b}")
old_node = vyper_ast.body[0].value
new_node = old_node.get_folded_value()
# force bounds check, no-op because validate_numeric_bounds
# already does this, but leave in for hygiene (in case
Expand All @@ -78,10 +77,9 @@ def foo(a: int256, b: uint256) -> int256:
"""
contract = get_contract(source)

vyper_ast = vy_ast.parse_to_ast(f"{a} {op} {b}")
old_node = vyper_ast.body[0].value

try:
vyper_ast = parse_and_fold(f"{a} {op} {b}")
old_node = vyper_ast.body[0].value
new_node = old_node.get_folded_value()
validate_expected_type(new_node, INT256_T) # force bounds check
# compile time behavior does not match runtime behavior.
Expand All @@ -105,7 +103,7 @@ def foo(a: uint256) -> uint256:
"""
contract = get_contract(source)

vyper_ast = vy_ast.parse_to_ast(f"~{value}")
vyper_ast = parse_and_fold(f"~{value}")
old_node = vyper_ast.body[0].value
new_node = old_node.get_folded_value()

Expand Down
7 changes: 3 additions & 4 deletions tests/functional/builtins/folding/test_epsilon.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pytest

from vyper import ast as vy_ast
from vyper.builtins import functions as vy_fn
from tests.utils import parse_and_fold


@pytest.mark.parametrize("typ_name", ["decimal"])
Expand All @@ -13,8 +12,8 @@ def foo() -> {typ_name}:
"""
contract = get_contract(source)

vyper_ast = vy_ast.parse_to_ast(f"epsilon({typ_name})")
vyper_ast = parse_and_fold(f"epsilon({typ_name})")
old_node = vyper_ast.body[0].value
new_node = vy_fn.DISPATCH_TABLE["epsilon"]._try_fold(old_node)
new_node = old_node.get_folded_value()

assert contract.foo() == new_node.value
7 changes: 3 additions & 4 deletions tests/functional/builtins/folding/test_floor_ceil.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
from hypothesis import example, given, settings
from hypothesis import strategies as st

from vyper import ast as vy_ast
from vyper.builtins import functions as vy_fn
from tests.utils import parse_and_fold

st_decimals = st.decimals(
min_value=-(2**32), max_value=2**32, allow_nan=False, allow_infinity=False, places=10
Expand All @@ -28,8 +27,8 @@ def foo(a: decimal) -> int256:
"""
contract = get_contract(source)

vyper_ast = vy_ast.parse_to_ast(f"{fn_name}({value})")
vyper_ast = parse_and_fold(f"{fn_name}({value})")
old_node = vyper_ast.body[0].value
new_node = vy_fn.DISPATCH_TABLE[fn_name]._try_fold(old_node)
new_node = old_node.get_folded_value()

assert contract.foo(value) == new_node.value
Loading

0 comments on commit 8fecd11

Please sign in to comment.