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

feat[lang]: add blobhash() builtin #3962

Merged
merged 22 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
24 changes: 24 additions & 0 deletions docs/built-in-functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,30 @@ Utilities
>>> ExampleContract.foo()
0xf3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

.. py:function:: blobhash(index: uint256) -> bytes32

Return the versioned hash of the ``index``-th BLOB associated with the current transaction.

.. note::

A versioned hash consists of a single byte representing the version (currently ``0x01``), followed by the last 31 bytes of the ``SHA256`` hash of the KZG commitment (`EIP-4844 <https://eips.ethereum.org/EIPS/eip-4844>`_). For the case ``index >= len(tx.blob_versioned_hashes)``, `blobhash(index: uint256)` returns ``empty(bytes32)``.

.. code-block:: vyper

@external
@view
def foo(index: uint256) -> bytes32:
return blobhash(index)

.. code-block:: vyper

>>> ExampleContract.foo(0)
0xfd28610fb309939bfec12b6db7c4525446f596a5a5a66b8e2cb510b45b2bbeb5

>>> ExampleContract.foo(6)
0x0000000000000000000000000000000000000000000000000000000000000000


.. py:function:: empty(typename) -> Any

Return a value which is the default (zero-ed) value of its type. Useful for initializing new memory variables.
Expand Down
52 changes: 52 additions & 0 deletions tests/functional/builtins/codegen/test_blobhash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import pytest
from pytest import raises
Fixed Show fixed Hide fixed

from vyper import compiler
from vyper.exceptions import EvmVersionException
Fixed Show fixed Hide fixed

valid_list = [
"""
@external
@view
def foo() -> bytes32:
return blobhash(0)
""",
"""
@external
@view
def foo() -> bytes32:
a: bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000005
a = blobhash(2)
return a
""",
"""
@external
@view
def foo() -> bytes32:
a: bytes32 = blobhash(5)
return a
""",
"""
@external
@view
def foo() -> bytes32:
a: bytes32 = blobhash(1337)
assert a == empty(bytes32)
return a
""",
]


@pytest.mark.requires_evm_version("cancun")
@pytest.mark.parametrize("good_code", valid_list)
def test_blobhash_success(good_code):
assert compiler.compile_code(good_code) is not None
assembly = compiler.compile_code(good_code, output_formats=["asm"])["asm"].split(" ")
assert "BLOBHASH" in assembly


@pytest.mark.requires_evm_version("shanghai")
pcaversaccio marked this conversation as resolved.
Show resolved Hide resolved
@pytest.mark.parametrize("invalid_evm_version", valid_list)
def test_blobhash_fail(invalid_evm_version):
with pytest.raises(EvmVersionException):
compiler.compile_code(invalid_evm_version)
18 changes: 18 additions & 0 deletions vyper/builtins/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@
from vyper.codegen.expr import Expr
from vyper.codegen.ir_node import Encoding, scope_multi
from vyper.codegen.keccak256_helper import keccak256_helper
from vyper.evm.opcodes import version_check
from vyper.evm.address_space import MEMORY
from vyper.exceptions import (
ArgumentException,
CompilerPanic,
EvmVersionException,
InvalidLiteral,
InvalidType,
StateAccessViolation,
Expand Down Expand Up @@ -1219,6 +1221,21 @@ def build_IR(self, expr, args, kwargs, contact):
)


class BlobHash(BuiltinFunctionT):
_id = "blobhash"
_inputs = [("index", UINT256_T)]
_return_type = BYTES32_T

@process_inputs
def build_IR(self, expr, args, kwargs, contact):
if not version_check(begin="cancun"):
charles-cooper marked this conversation as resolved.
Show resolved Hide resolved
raise EvmVersionException("`blobhash` is not available pre-cancun", expr)
return IRnode.from_list(
["blockhash", args[0]],
typ=BYTES32_T,
)


class RawRevert(BuiltinFunctionT):
_id = "raw_revert"
_inputs = [("data", BytesT.any())]
Expand Down Expand Up @@ -2591,6 +2608,7 @@ def _try_fold(self, node):
"as_wei_value": AsWeiValue(),
"raw_call": RawCall(),
"blockhash": BlockHash(),
"blobhash": BlobHash(),
"bitwise_and": BitwiseAnd(),
"bitwise_or": BitwiseOr(),
"bitwise_xor": BitwiseXor(),
Expand Down
1 change: 1 addition & 0 deletions vyper/evm/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"CHAINID": (0x46, 0, 1, 2),
"SELFBALANCE": (0x47, 0, 1, 5),
"BASEFEE": (0x48, 0, 1, 2),
"BLOBHASH": (0x49, 1, 1, (None, None, None, 2)),
"POP": (0x50, 1, 0, 2),
"MLOAD": (0x51, 1, 1, 3),
"MSTORE": (0x52, 2, 0, 3),
Expand Down
1 change: 1 addition & 0 deletions vyper/venom/ir_node_to_venom.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"balance",
"msize",
"basefee",
"blobhash",
"invalid",
"stop",
"selfdestruct",
Expand Down
1 change: 1 addition & 0 deletions vyper/venom/venom_to_assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"delegatecall",
"codesize",
"basefee",
"blobhash",
"prevrandao",
"difficulty",
"invalid",
Expand Down
Loading