Skip to content
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

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
90747ef
add blockhash to local validation
tserg Nov 24, 2022
393dfed
add test
tserg Nov 24, 2022
3d303c7
fix mypy lint
tserg Nov 24, 2022
439bb78
use StateMutability
tserg Nov 27, 2022
5fadb3b
fix lint
tserg Nov 27, 2022
d976d3f
Merge branch 'master' of https://github.com/vyperlang/vyper into fix/…
tserg Nov 28, 2022
aa82067
fix merge conflict
tserg Nov 28, 2022
cccd707
fix import
tserg Nov 28, 2022
6f193e4
Merge branch 'master' of https://github.com/vyperlang/vyper into fix/…
tserg May 18, 2023
a0e80ad
clean up imports
tserg May 18, 2023
b3e4b62
undo blank line
tserg May 18, 2023
79e1674
filter for nonpure builtins from namespace
tserg May 18, 2023
f6f2e91
fetch all call nodes
tserg May 18, 2023
a5b1924
clean up
tserg May 18, 2023
b754a1b
undo blank line
tserg May 18, 2023
eff8438
add interface test
tserg May 18, 2023
035a91b
fix lint
tserg May 18, 2023
9410901
Merge branch 'master' of https://github.com/vyperlang/vyper into fix/…
tserg Feb 21, 2024
f6c95b2
revert merge conflict
tserg Feb 21, 2024
19baa5d
some fixes
tserg Feb 21, 2024
a33c7a8
move raw_call check to fetch_call_return
tserg Mar 8, 2024
bf26d2e
fix lint
tserg Mar 8, 2024
7ae3018
Merge branch 'master' of https://github.com/vyperlang/vyper into fix/…
tserg Mar 8, 2024
c3f2bf6
fix test
tserg Mar 8, 2024
3931761
modify tests
tserg Mar 19, 2024
1895549
add default value
tserg Mar 19, 2024
9e52ecc
Merge branch 'master' into fix/blockhash
charles-cooper Mar 25, 2024
dad2c46
apply bts suggestion
tserg Mar 26, 2024
ebfe003
revert raw call changes
tserg Mar 26, 2024
4709936
fix lint
tserg Mar 26, 2024
e2e9864
Merge branch 'fix/blockhash' of https://github.com/tserg/vyper into f…
tserg Mar 26, 2024
b1517b7
Merge branch 'master' of https://github.com/vyperlang/vyper into fix/…
tserg Mar 27, 2024
d9e32c7
Merge branch 'master' of https://github.com/vyperlang/vyper into fix/…
tserg Oct 11, 2024
8610908
add blobhash
tserg Oct 11, 2024
36d6ddb
Merge branch 'master' of https://github.com/vyperlang/vyper into fix/…
tserg Oct 12, 2024
115f9c4
Merge branch 'master' into fix/blockhash
charles-cooper Dec 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions tests/parser/features/decorators/test_pure.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,35 @@ def foo() -> uint256:
),
FunctionDeclarationException,
)


def test_invalid_builtin(get_contract, assert_compile_failed):
assert_compile_failed(
lambda: get_contract(
"""
@external
@pure
def foo(x: uint256)-> bytes32:
return blockhash(x)
"""
),
StateAccessViolation,
)


def test_invalid_interface(get_contract, assert_compile_failed):
assert_compile_failed(
lambda: get_contract(
"""
interface Foo:
def foo() -> uint256: payable


@external
@pure
def bar(a: address) -> uint256:
return Foo(a).foo()
"""
),
StateAccessViolation,
)
2 changes: 2 additions & 0 deletions vyper/builtins/_signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from vyper.codegen.expr import Expr
from vyper.codegen.ir_node import IRnode
from vyper.exceptions import CompilerPanic, TypeMismatch
from vyper.semantics.analysis.base import StateMutability
from vyper.semantics.analysis.utils import get_exact_type_from_node, validate_expected_type
from vyper.semantics.types import TYPE_T, KwargSettings, VyperType
from vyper.semantics.types.utils import type_from_annotation
Expand Down Expand Up @@ -77,6 +78,7 @@ def decorator_fn(self, node, context):
class BuiltinFunction:
_has_varargs = False
_kwargs: Dict[str, KwargSettings] = {}
mutability = StateMutability.PURE

# helper function to deal with TYPE_DEFINITIONs
def _validate_single(self, arg, expected_type):
Expand Down
3 changes: 2 additions & 1 deletion vyper/builtins/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
UnfoldableNode,
ZeroDivisionException,
)
from vyper.semantics.analysis.base import VarInfo
from vyper.semantics.analysis.base import StateMutability, VarInfo
from vyper.semantics.analysis.utils import (
get_common_types,
get_exact_type_from_node,
Expand Down Expand Up @@ -1256,6 +1256,7 @@ class BlockHash(BuiltinFunction):
_id = "blockhash"
_inputs = [("block_num", UINT256_T)]
_return_type = BYTES32_T
mutability = StateMutability.VIEW

@process_inputs
def build_IR(self, expr, args, kwargs, contact):
Expand Down
16 changes: 15 additions & 1 deletion vyper/semantics/analysis/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
EventT,
HashMapT,
IntegerT,
InterfaceT,
SArrayT,
StringT,
StructT,
Expand Down Expand Up @@ -203,9 +204,22 @@ def __init__(
]
node_list.extend(standalone_self) # type: ignore

# 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:
Copy link
Member

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 ExprInfos, and then during local.py we can check at every single expression (and maybe statement too) whether expr_info.mutability > self.func.mutability.

# allowed
continue
raise StateAccessViolation(
Expand Down