feat[lang]: nonreentrancy by default#4563
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #4563 +/- ##
==========================================
- Coverage 92.50% 92.49% -0.01%
==========================================
Files 128 128
Lines 18432 18506 +74
Branches 3191 3208 +17
==========================================
+ Hits 17050 17118 +68
- Misses 941 944 +3
- Partials 441 444 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
as discussed offline, we should also process the pragma for imports |
|
this fails, imo we should only restrict the pragma to external functions def test_nonreentrant_decorator(get_contract):
code = """
# pragma nonreentrancy on
def foo():
u: uint256 = 1
@external
def bar():
self.foo()
"""
c = get_contract(code)
c.bar() |
which is problematic because |
remove `parse_to_ast_with_settings`, and replace it with directly putting the settings parsed from the pragmas on the AST. this allows us to respect pragmas on a file-by-file basis if needed.
it's duplicated with vyper/ast/utils.py
6516d49 to
655ec47
Compare
|
per Anatomist: |
|
Per Anatomist: I don't think this is a huge deal but if we can bake semantics into the grammar while not sacrificing simplicity, we should do it. |
nonreentrancy fixes
|
Let's make sure the docs are up-to-date with the latest changes. Including a comment from Anatomist. Didn't yet check whether it's relevant for the latest commit: |
@trocher further mentions: In However, this does not account for the a: public(reentrant(constant(uint256))) = 1 |
i think it's fine to allow these kinds of things in the grammar, |
|
Per @trocher In the case no nonreentrant functions are present in the contract, but only public state variables with the The following contracts yield the given layout when running # pragma nonreentrancy on
a: public(constant(uint256)) = 1
b: transient(uint256){"transient_storage_layout": {"b": {"type": "uint256", "n_slots": 1, "slot": 1}}} |
This has further impact down the line because we test for round-trip when using overrides. Because of the missing key, contracts will stop compiling: note that i used |
lifted this into a separate issue: #4610 |
lifted this to: #4611 |
lifted this up to #4612 |
docs/control-structures.rst
Outdated
| The nonreentrant pragma | ||
| ----------------------- | ||
|
|
||
| Beginning in 0.4.2, the ``#pragma nonreentrancy on`` pragma is available, and it enables nonreentrancy on all functions and public getters in the file. This is to prepare for a future release, probably in the 0.5.x series, where nonreentrant locks will be enabled by default language-wide. |
There was a problem hiding this comment.
on all external functions
There was a problem hiding this comment.
we should document how it behaves for:
- internal functions
- pure external functions
- view external functions
docs/control-structures.rst
Outdated
| # pragma nonreentrancy on | ||
|
|
||
| x: public(uint256) # this has view-only reentrancy turned on | ||
| y: public(reentrant(uint256)) # this does not have view-only reentrancy |
| def __default__(): | ||
| # the default function is reentrant by default, even when | ||
| # the nonreentrancy pragma is set | ||
| # this function is nonreentrant! |
There was a problem hiding this comment.
for make_a_call the comment says # this function is protected from re-entrancy, the inconsistency makes it a bit hard to read
docs/control-structures.rst
Outdated
| .. code-block:: vyper | ||
| # pragma nonreentrancy on | ||
|
|
||
| x: public(uint256) # this has view-only reentrancy turned on |
There was a problem hiding this comment.
getters are by default nonreentrant with the pragma on
…eentrancy-by-default improve nonreentrant pragma docs
What I did
implements #3380, #4509
How I did it
How to verify it
Commit message
Description for the changelog
Cute Animal Picture