Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9a20c1edb | ||
|
|
c492e40fd2 |
11 changed files with 21 additions and 384 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1 +1 @@
|
|||
/vyper-0.4.0.tar.gz
|
||||
/vyper-[0-9]*.[0-9]*.[0-9]*.tar.gz
|
||||
|
|
|
|||
2
sources
2
sources
|
|
@ -1 +1 @@
|
|||
SHA512 (vyper-0.4.0.tar.gz) = 0ad76740ba745a554ccbdc938a8f71a4df22bc9e459e645b128d1cfebcc54975e0941976874fc26196c9149c12e44bdb5d5be18ec2a9b0fecb31a2a9c530b98c
|
||||
SHA512 (vyper-0.4.1.tar.gz) = 98d03ae6cd7d268b5292f52ac2b7a7b24e3250674a959afff1cc95ce17cde534416381c80e66d5a29c0b6e970557f5f6e52396e714abfd3c4bd745deb8a02cda
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Subject: [PATCH] Use Cryptodomex
|
|||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
diff --git a/setup.py b/setup.py
|
||||
index 6e48129c..e2b0688d 100644
|
||||
index e6d4c576..28ba7ebd 100644
|
||||
--- a/setup.py
|
||||
+++ b/setup.py
|
||||
@@ -92,7 +92,7 @@ setup(
|
||||
|
|
@ -15,13 +15,13 @@ index 6e48129c..e2b0688d 100644
|
|||
- "pycryptodome>=3.5.1,<4",
|
||||
+ "pycryptodomex>=3.5.1,<4",
|
||||
"packaging>=23.1,<24",
|
||||
"lark>=1.0.0,<2",
|
||||
"importlib-metadata",
|
||||
"wheel",
|
||||
diff --git a/vyper/utils.py b/vyper/utils.py
|
||||
index 2b95485f..1968c281 100644
|
||||
index d1327475..9e5f5863 100644
|
||||
--- a/vyper/utils.py
|
||||
+++ b/vyper/utils.py
|
||||
@@ -184,7 +184,7 @@ decimal.setcontext(DecimalContextOverride(prec=78))
|
||||
@@ -217,7 +217,7 @@ decimal.setcontext(DecimalContextOverride(prec=78))
|
||||
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -5,20 +5,21 @@ Subject: [PATCH] Ease version requirements
|
|||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
diff --git a/setup.py b/setup.py
|
||||
index e2b0688d..82755981 100644
|
||||
index 28ba7ebd..2dd2d9b9 100644
|
||||
--- a/setup.py
|
||||
+++ b/setup.py
|
||||
@@ -93,11 +93,11 @@ setup(
|
||||
@@ -93,12 +93,12 @@ setup(
|
||||
"cbor2>=5.4.6,<6",
|
||||
"asttokens>=2.0.5,<3",
|
||||
"pycryptodomex>=3.5.1,<4",
|
||||
- "packaging>=23.1,<24",
|
||||
+ "packaging>=23.1",
|
||||
"lark>=1.0.0,<2",
|
||||
"importlib-metadata",
|
||||
"wheel",
|
||||
],
|
||||
- setup_requires=["pytest-runner", "setuptools_scm>=7.1.0,<8.0.0"],
|
||||
+ setup_requires=["pytest-runner", "setuptools_scm>=7.1.0"],
|
||||
tests_require=extras_require["test"],
|
||||
- setup_requires=["setuptools_scm>=7.1.0,<8.0.0"],
|
||||
+ setup_requires=["setuptools_scm>=7.1.0"],
|
||||
extras_require=extras_require,
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
|
|
|
|||
|
|
@ -1,27 +1,19 @@
|
|||
From: Peter Lemenkov <lemenkov@gmail.com>
|
||||
Date: Thu, 25 Jul 2024 23:18:23 +0200
|
||||
Subject: [PATCH] Lark should go to the main install section as it used not
|
||||
only for tests
|
||||
Subject: [PATCH] Relax lark dependency
|
||||
|
||||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
diff --git a/setup.py b/setup.py
|
||||
index 82755981..94477f03 100644
|
||||
index 2dd2d9b9..0a3367ca 100644
|
||||
--- a/setup.py
|
||||
+++ b/setup.py
|
||||
@@ -15,7 +15,6 @@ extras_require = {
|
||||
@@ -15,7 +15,7 @@ extras_require = {
|
||||
"pytest-split>=0.7.0,<1.0",
|
||||
"eth_abi>=5.0.0,<6.0.0",
|
||||
"py-evm>=0.10.1b1,<0.11",
|
||||
- "lark==1.1.9",
|
||||
+ "lark>=1.1.7",
|
||||
"hypothesis[lark]>=6.0,<7.0",
|
||||
"eth-stdlib==0.2.7",
|
||||
"eth-account==0.12.2",
|
||||
@@ -92,6 +91,7 @@ setup(
|
||||
install_requires=[
|
||||
"cbor2>=5.4.6,<6",
|
||||
"asttokens>=2.0.5,<3",
|
||||
+ "lark==1.1.9",
|
||||
"pycryptodomex>=3.5.1,<4",
|
||||
"packaging>=23.1",
|
||||
"importlib-metadata",
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
From: Peter Lemenkov <lemenkov@gmail.com>
|
||||
Date: Thu, 8 Aug 2024 20:33:53 +0200
|
||||
Subject: [PATCH] Relax lark requirement (testing only anyway)
|
||||
|
||||
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
|
||||
|
||||
diff --git a/setup.py b/setup.py
|
||||
index 94477f03..61cf2f76 100644
|
||||
--- a/setup.py
|
||||
+++ b/setup.py
|
||||
@@ -91,7 +91,7 @@ setup(
|
||||
install_requires=[
|
||||
"cbor2>=5.4.6,<6",
|
||||
"asttokens>=2.0.5,<3",
|
||||
- "lark==1.1.9",
|
||||
+ "lark>=1.1.7",
|
||||
"pycryptodomex>=3.5.1,<4",
|
||||
"packaging>=23.1",
|
||||
"importlib-metadata",
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
From: Charles Cooper <cooper.charles.m@gmail.com>
|
||||
Date: Sun, 23 Feb 2025 10:38:22 +0100
|
||||
Subject: [PATCH] fix[lang]: define rounding mode for sqrt (#4486)
|
||||
|
||||
prior to this commit, the rounding mode for `sqrt()` is undefined,
|
||||
which could be an issue for applications which use `sqrt()` to
|
||||
determine boundary conditions. this commit ensures the result is
|
||||
rounded down.
|
||||
|
||||
diff --git a/docs/built-in-functions.rst b/docs/built-in-functions.rst
|
||||
index a0e424ad..6ac659bd 100644
|
||||
--- a/docs/built-in-functions.rst
|
||||
+++ b/docs/built-in-functions.rst
|
||||
@@ -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
|
||||
|
||||
diff --git a/tests/functional/codegen/types/numbers/test_sqrt.py b/tests/functional/codegen/types/numbers/test_sqrt.py
|
||||
index cf62cecd..54b762c4 100644
|
||||
--- a/tests/functional/codegen/types/numbers/test_sqrt.py
|
||||
+++ b/tests/functional/codegen/types/numbers/test_sqrt.py
|
||||
@@ -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)
|
||||
diff --git a/vyper/builtins/functions.py b/vyper/builtins/functions.py
|
||||
index 672d9784..5c7e3a6a 100644
|
||||
--- a/vyper/builtins/functions.py
|
||||
+++ b/vyper/builtins/functions.py
|
||||
@@ -2142,6 +2142,9 @@ else:
|
||||
break
|
||||
y = z
|
||||
z = (x / z + z) / 2.0
|
||||
+
|
||||
+ if y < z:
|
||||
+ z = y
|
||||
"""
|
||||
|
||||
x_type = DecimalT()
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
From: Charles Cooper <cooper.charles.m@gmail.com>
|
||||
Date: Sat, 22 Feb 2025 19:34:41 +0100
|
||||
Subject: [PATCH] fix[codegen]: cache result of iter eval (#4488)
|
||||
|
||||
prior to this commit, multiple evaluation of a single expression is
|
||||
possible in the iterator target of a for loop. while the iterator
|
||||
expression cannot produce multiple writes, it can _consume_ side
|
||||
effects produced in the loop body (e.g. read a storage variable
|
||||
updated in the loop body) and thus lead to unexpected program
|
||||
behavior. specifically, reads in iterators which contain an `IfExp`
|
||||
(e.g. `for s: uint256 in ([read(), read()] if True else []))` would
|
||||
issue one evaluation of the list `[read(), read()]` per loop iteration,
|
||||
thus interleaving reads with writes in the loop body.
|
||||
|
||||
this commit fixes the issue by using `cache_when_complex` to enforce
|
||||
evaluation of the iterator before entering the loop body.
|
||||
|
||||
this is incidentally also a performance fix, since it moves the
|
||||
repeated evaluation into a one-time evaluation.
|
||||
|
||||
references:
|
||||
- https://github.com/vyperlang/vyper/security/advisories/GHSA-h33q-mhmp-8p67
|
||||
|
||||
diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py
|
||||
index 830f2f92..165252d5 100644
|
||||
--- a/vyper/codegen/stmt.py
|
||||
+++ b/vyper/codegen/stmt.py
|
||||
@@ -267,20 +267,21 @@ class Stmt:
|
||||
ret.append(make_setter(tmp_list, iter_list))
|
||||
iter_list = tmp_list
|
||||
|
||||
- # set up the loop variable
|
||||
- e = get_element_ptr(iter_list, i, array_bounds_check=False)
|
||||
- body = ["seq", make_setter(loop_var, e), parse_body(self.stmt.body, self.context)]
|
||||
-
|
||||
- repeat_bound = iter_list.typ.count
|
||||
- if isinstance(iter_list.typ, DArrayT):
|
||||
- array_len = get_dyn_array_count(iter_list)
|
||||
- else:
|
||||
- array_len = repeat_bound
|
||||
+ with iter_list.cache_when_complex("list_iter") as (b1, iter_list):
|
||||
+ # set up the loop variable
|
||||
+ e = get_element_ptr(iter_list, i, array_bounds_check=False)
|
||||
+ body = ["seq", make_setter(loop_var, e), parse_body(self.stmt.body, self.context)]
|
||||
+
|
||||
+ repeat_bound = iter_list.typ.count
|
||||
+ if isinstance(iter_list.typ, DArrayT):
|
||||
+ array_len = get_dyn_array_count(iter_list)
|
||||
+ else:
|
||||
+ array_len = repeat_bound
|
||||
|
||||
- ret.append(["repeat", i, 0, array_len, repeat_bound, body])
|
||||
+ ret.append(["repeat", i, 0, array_len, repeat_bound, body])
|
||||
|
||||
- del self.context.forvars[varname]
|
||||
- return IRnode.from_list(ret)
|
||||
+ del self.context.forvars[varname]
|
||||
+ return b1.resolve(IRnode.from_list(ret))
|
||||
|
||||
def parse_AugAssign(self):
|
||||
target = self._get_target(self.stmt.target)
|
||||
diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py
|
||||
index 26c6a4ef..909f5b7b 100644
|
||||
--- a/vyper/semantics/analysis/local.py
|
||||
+++ b/vyper/semantics/analysis/local.py
|
||||
@@ -522,6 +522,7 @@ class FunctionAnalyzer(VyperNodeVisitorBase):
|
||||
def _analyse_range_iter(self, iter_node, target_type):
|
||||
# iteration via range()
|
||||
if iter_node.get("func.id") != "range":
|
||||
+ # CMC 2025-02-12 I think we can allow this actually
|
||||
raise IteratorException("Cannot iterate over the result of a function call", iter_node)
|
||||
_validate_range_call(iter_node)
|
||||
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
From: Charles Cooper <cooper.charles.m@gmail.com>
|
||||
Date: Sun, 23 Feb 2025 20:51:52 +0100
|
||||
Subject: [PATCH] fix[codegen]: disable augassign with overlap (#4487)
|
||||
|
||||
in vyper, the behavior for AugAssign is to perform the bounds checks
|
||||
only before evaluation of the rhs, rather than before-and-after. in
|
||||
other words, the following code:
|
||||
|
||||
```vyper
|
||||
def poc():
|
||||
a: DynArray[uint256, 2] = [1, 2]
|
||||
a[1] += a.pop()
|
||||
```
|
||||
|
||||
is equivalent to:
|
||||
|
||||
```vyper
|
||||
def poc():
|
||||
a: DynArray[uint256, 2] = [1, 2]
|
||||
a[1] += a[len(a) - 1]
|
||||
a.pop()
|
||||
```
|
||||
|
||||
rather than:
|
||||
|
||||
```vyper
|
||||
def poc():
|
||||
a: DynArray[uint256, 2] = [1, 2]
|
||||
s: uint256 = a[1]
|
||||
t: uint256 = a.pop()
|
||||
a[1] = s + t # reverts due to oob access
|
||||
```
|
||||
|
||||
this commit blocks the potentially missing bounds check by panicking
|
||||
when there is a potential write on the rhs of an AugAssign which could
|
||||
change the length on the lhs.
|
||||
|
||||
references:
|
||||
- https://github.com/vyperlang/vyper/security/advisories/GHSA-4w26-8p97-f4jp
|
||||
|
||||
---------
|
||||
|
||||
Co-authored-by: cyberthirst <cyberthirst.eth@gmail.com>
|
||||
|
||||
diff --git a/tests/functional/codegen/features/test_assignment.py b/tests/functional/codegen/features/test_assignment.py
|
||||
index eaafb527..53d02dfb 100644
|
||||
--- a/tests/functional/codegen/features/test_assignment.py
|
||||
+++ b/tests/functional/codegen/features/test_assignment.py
|
||||
@@ -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):
|
||||
@@ -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",
|
||||
[
|
||||
diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py
|
||||
index 165252d5..24391e27 100644
|
||||
--- a/vyper/codegen/stmt.py
|
||||
+++ b/vyper/codegen/stmt.py
|
||||
@@ -293,6 +293,13 @@ class Stmt:
|
||||
# single word load/stores are atomic.
|
||||
raise TypeCheckFailure("unreachable")
|
||||
|
||||
+ for var in target.referenced_variables:
|
||||
+ if var.typ._is_prim_word:
|
||||
+ continue
|
||||
+ # oob - GHSA-4w26-8p97-f4jp
|
||||
+ if var in right.variable_writes or right.contains_risky_call:
|
||||
+ raise CodegenPanic("unreachable")
|
||||
+
|
||||
with target.cache_when_complex("_loc") as (b, target):
|
||||
left = IRnode.from_list(LOAD(target), typ=target.typ)
|
||||
new_val = Expr.handle_binop(self.stmt.op, left, right, self.context)
|
||||
13
vyper.spec
13
vyper.spec
|
|
@ -1,8 +1,8 @@
|
|||
%global git_commit e9db8d9f7486eae38f5b86531629019ad28f514e
|
||||
%global git_commit 8a93dd27de503b0a3ace36d961a10c9ea4adee8b
|
||||
|
||||
Summary: Pythonic Smart Contract Language for the EVM
|
||||
Name: vyper
|
||||
Version: 0.4.0
|
||||
Version: 0.4.1
|
||||
Release: %autorelease
|
||||
BuildArch: noarch
|
||||
License: Apache-2.0
|
||||
|
|
@ -10,12 +10,8 @@ URL: https://vyperlang.org
|
|||
Source0: %{pypi_source %{name}}
|
||||
Patch1: vyper-0001-Use-Cryptodomex.patch
|
||||
Patch2: vyper-0002-Ease-version-requirements.patch
|
||||
Patch3: vyper-0003-Lark-should-go-to-the-main-install-section-as-it-use.patch
|
||||
Patch4: vyper-0004-Remove-unnecessary-shebang.patch
|
||||
Patch5: vyper-0005-Relax-lark-requirement-testing-only-anyway.patch
|
||||
Patch6: vyper-0006-fix-lang-define-rounding-mode-for-sqrt-4486.patch
|
||||
Patch7: vyper-0007-fix-codegen-cache-result-of-iter-eval-4488.patch
|
||||
Patch8: vyper-0008-fix-codegen-disable-augassign-with-overlap-4487.patch
|
||||
Patch3: vyper-0003-Remove-unnecessary-shebang.patch
|
||||
Patch4: vyper-0004-Relax-lark-dependency.patch
|
||||
BuildRequires: git
|
||||
BuildRequires: python3-cached_property
|
||||
BuildRequires: python3-devel
|
||||
|
|
@ -53,6 +49,7 @@ rm -f %{buildroot}/usr/vyper_git_commithash.txt
|
|||
%files -f %{pyproject_files}
|
||||
%doc README.md SECURITY.md
|
||||
%{_bindir}/fang
|
||||
%{_bindir}/venom
|
||||
%{_bindir}/vyper
|
||||
%{_bindir}/vyper-json
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue