-
-
Notifications
You must be signed in to change notification settings - Fork 802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix[lang]: disallow blockhash
in pure
functions
#3157
base: master
Are you sure you want to change the base?
Conversation
An alternative and perhaps more scalable approach is to add a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea, i think the clearer and more maintainable approach would be to set the mutability of the builtin correctly
Codecov ReportAll modified and coverable lines are covered by tests ✅
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #3157 +/- ##
==========================================
+ Coverage 86.34% 86.38% +0.03%
==========================================
Files 92 92
Lines 14028 14026 -2
Branches 3083 3081 -2
==========================================
+ Hits 12113 12116 +3
+ Misses 1487 1483 -4
+ Partials 428 427 -1 ☔ View full report in Codecov by Sentry. |
vyper/semantics/validation/local.py
Outdated
from vyper.builtin_functions.functions import BUILTIN_FUNCTIONS | ||
builtin_fns = fn_node.get_descendants(vy_ast.Name, {"id": set(BUILTIN_FUNCTIONS)}) | ||
|
||
node_list.extend(builtin_fns) # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To add builtin function calls to the list of nodes to check. Or should the check for builtin functions be performed elsewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh for some reason i thought the mutability check was performed under visit_Call. i guess this solution is ok for now; i want to get in #2974 first though
I have changed the approach to one that also fixes #3425. |
vyper/semantics/analysis/local.py
Outdated
# Add all calls except structs | ||
filtered_call_nodes = [ | ||
c.func | ||
for c in fn_node.get_descendants(vy_ast.Call) | ||
if not (len(c.args) == 1 and isinstance(c.args[0], vy_ast.Dict)) | ||
] | ||
node_list.extend(filtered_call_nodes) # type: ignore | ||
|
||
for node in node_list: | ||
t = node._metadata.get("type") | ||
if isinstance(t, ContractFunctionT) and t.mutability == StateMutability.PURE: | ||
# skip structs and interface instantiation | ||
if isinstance(t, StructT) or is_type_t(t, InterfaceT): | ||
continue | ||
|
||
# skip ContractFunctionT and BuiltinFunction with mutability set to pure | ||
if hasattr(t, "mutability") and t.mutability == StateMutability.PURE: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think the ast analysis is still not the way to go. i think probably a better approach is to add a mutability
to all ExprInfo
s, and then during local.py
we can check at every single expression (and maybe statement too) whether expr_info.mutability > self.func.mutability
.
this is looking better. i'm still hesitant though, because i tried this myself and realized that the approach doesn't work for |
vyper/builtins/functions.py
Outdated
@@ -1061,6 +1061,25 @@ def fetch_call_return(self, node): | |||
|
|||
kwargz = {i.arg: i.value for i in node.keywords} | |||
|
|||
delegate_call = kwargz.get("is_delegate_call") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if the user passes is_delegate_call=False
?
vyper/builtins/functions.py
Outdated
if (delegate_call or static_call) and value is not None: | ||
raise ArgumentException("value= may not be passed for static or delegate calls!") | ||
|
||
fn_node = node.get_ancestor(vy_ast.FunctionDef) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note for refactoring: ideally we should pass this in a context object
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should I add a comment here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
@@ -900,25 +900,29 @@ def set_lucky(arg1: address, arg2: int128): | |||
print("Successfully executed an external contract call state change") | |||
|
|||
|
|||
def test_constant_external_contract_call_cannot_change_state(): | |||
c = """ | |||
@pytest.mark.parametrize("state_modifying_decorator", ("payable", "nonpayable")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pytest.mark.parametrize("state_modifying_decorator", ("payable", "nonpayable")) | |
@pytest.mark.parametrize("modifying", ("payable", "nonpayable")) |
def test_constant_external_contract_call_cannot_change_state(): | ||
c = """ | ||
@pytest.mark.parametrize("state_modifying_decorator", ("payable", "nonpayable")) | ||
@pytest.mark.parametrize("non_modifying_decorator", ("pure", "view")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pytest.mark.parametrize("non_modifying_decorator", ("pure", "view")) | |
@pytest.mark.parametrize("constant", ("pure", "view")) |
def test_constant_external_contract_call_cannot_change_state(): | ||
c = """ | ||
@pytest.mark.parametrize("state_modifying_decorator", ("payable", "nonpayable")) | ||
@pytest.mark.parametrize("non_modifying_decorator", ("pure", "view")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pytest.mark.parametrize("non_modifying_decorator", ("pure", "view")) | |
@pytest.mark.parametrize("constant", ("pure", "view")) |
vyper/builtins/functions.py
Outdated
@@ -1061,6 +1061,26 @@ def fetch_call_return(self, node): | |||
|
|||
kwargz = {i.arg: i.value for i in node.keywords} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe get i.get_folded_value().value
here
blockhash
in pure
functionsblockhash
in pure
functions
let's revert the changes to raw_call here because they seem a bit out of scope; we can revisit in another PR. |
@@ -6,7 +6,7 @@ | |||
from vyper.codegen.expr import Expr | |||
from vyper.codegen.ir_node import IRnode | |||
from vyper.exceptions import CompilerPanic, TypeMismatch, UnfoldableNode | |||
from vyper.semantics.analysis.base import Modifiability | |||
from vyper.semantics.analysis.base import Modifiability, StateMutability |
Check notice
Code scanning / CodeQL
Cyclic import Note
vyper.semantics.analysis.base
@@ -53,7 +53,7 @@ | |||
UnfoldableNode, | |||
ZeroDivisionException, | |||
) | |||
from vyper.semantics.analysis.base import Modifiability, VarInfo | |||
from vyper.semantics.analysis.base import Modifiability, StateMutability, VarInfo |
Check notice
Code scanning / CodeQL
Cyclic import Note
vyper.semantics.analysis.base
should we do the same for |
Yes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I revert the changes in this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably not. do any of them fail? it increases test coverage, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably not. do any of them fail? it increases test coverage, right?
no, they pass, and probably increases test coverage. I will leave this file as it is then.
What I did
Fix #3141.
How I did it
Check for
Name
nodes withblockhash
in local validation of pure functions.How to verify it
See test.
Commit message
fix: disallow
blockhash
inpure
functionsDescription for the changelog
Disallow
blockhash
inpure
functionsCute Animal Picture