Skip to content

Commit

Permalink
Deprecate SELFDESTRUCT starting at Shanghai only
Browse files Browse the repository at this point in the history
- Add a deprecate method wrapper
- Use this to wrap the opcode instructions for ``SELFDESTRUCT`` in the ``SHANGHAI_OPCODES``
- Add tests to make sure the deprecation warning is only listed for ``SELFDESTRUCT`` and only within the Shanghai VM
  • Loading branch information
fselmo committed Mar 7, 2023
1 parent fdc40f7 commit 9d445ed
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 15 deletions.
27 changes: 27 additions & 0 deletions eth/tools/_utils/deprecation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import functools
import warnings
from typing import (
Any,
Callable,
TypeVar,
cast,
)


TFunc = TypeVar("TFunc", bound=Callable[..., Any])


def deprecate_method(func: TFunc, message: str = None) -> TFunc:
@functools.wraps(func)
def deprecated_func(*args: Any, **kwargs: Any) -> Any:
warnings.warn(
category=DeprecationWarning,
message=(
message
or f"{func.__name__} is deprecated. "
"A breaking change is expected in a future release."
),
)
func(*args, **kwargs)

return cast(TFunc, deprecated_func)
13 changes: 0 additions & 13 deletions eth/vm/computation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import itertools
import warnings
from types import TracebackType
from typing import (
Any,
Expand All @@ -14,8 +13,6 @@
)

from cached_property import cached_property

from eth.vm import mnemonics, opcode_values
from eth_typing import (
Address,
)
Expand Down Expand Up @@ -551,16 +548,6 @@ def apply_computation(cls,
)

try:
# EIP-6049 - deprecate SELFDESTRUCT
if opcode == opcode_values.SELFDESTRUCT:
warnings.warn(
category=DeprecationWarning,
message=f"{mnemonics.SELFDESTRUCT} opcode present in "
"computation. This opcode is deprecated and a "
"breaking change to its functionality is likely to "
"come in the future."
)

opcode_fn(computation=computation)
except Halt:
break
Expand Down
11 changes: 10 additions & 1 deletion eth/vm/forks/shanghai/opcodes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import copy
from typing import Dict

from eth.tools._utils.deprecation import deprecate_method
from eth.vm.opcode import as_opcode
from eth_utils.toolz import merge

Expand All @@ -21,9 +22,17 @@
mnemonic=mnemonics.PUSH0,
gas_cost=constants.GAS_BASE,
),
opcode_values.SELFDESTRUCT: deprecate_method(
PARIS_OPCODES[opcode_values.SELFDESTRUCT],
message=(
f"{mnemonics.SELFDESTRUCT} opcode present in computation. This opcode is "
"deprecated and a breaking change to its functionality is likely to come "
"in the future."
),
),
}

SHANGHAI_OPCODES: Dict[int, OpcodeAPI] = merge(
copy.deepcopy(PARIS_OPCODES),
NEW_OPCODES
NEW_OPCODES,
)
57 changes: 56 additions & 1 deletion tests/core/opcodes/test_opcodes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import warnings

import pytest

from eth.chains.mainnet import (
MAINNET_VMS,
POS_MAINNET_VMS,
)
from eth.vm.forks.shanghai.computation import (
ShanghaiComputation,
)
from eth_utils import (
decode_hex,
encode_hex,
Expand Down Expand Up @@ -45,6 +54,7 @@
MuirGlacierVM,
BerlinVM,
LondonVM,
ShanghaiVM,
)
from eth.vm.message import (
Message,
Expand Down Expand Up @@ -75,7 +85,9 @@ def setup_vm(vm_class, chain_id=None):
db = AtomicDB()
chain_context = ChainContext(chain_id)
genesis_header = vm_class.create_genesis_header(
difficulty=constants.GENESIS_DIFFICULTY,
difficulty=(
constants.GENESIS_DIFFICULTY if vm_class not in POS_MAINNET_VMS else 0
),
timestamp=0,
)
return vm_class(genesis_header, ChainDB(db), chain_context, ConsensusContext(db))
Expand Down Expand Up @@ -1571,3 +1583,46 @@ def test_blake2b_f_compression(vm_class, input_hex, output_hex, expect_exception
comp.raise_if_error()
result = comp.output
assert result.hex() == output_hex


@pytest.mark.parametrize('vm_class', MAINNET_VMS[:13]) # vms up to Shanghai
def test_selfdestruct_does_not_issue_deprecation_warning_pre_shanghai(vm_class):
# assert no warning without selfdestruct
with warnings.catch_warnings():
warnings.simplefilter("error")

run_computation(
setup_vm(vm_class),
CANONICAL_ADDRESS_B,
code=assemble(opcode_values.SELFDESTRUCT),
)


def test_selfdestruct_issues_deprecation_warning_for_shanghai():
available_vm_opcodes = ShanghaiComputation.opcodes

vm_opcodes_without_selfdestruct = {
k: available_vm_opcodes[k] for k in available_vm_opcodes.keys()
if k != opcode_values.SELFDESTRUCT
}
code_without_self_destruct = assemble(
*[opc for opc in vm_opcodes_without_selfdestruct.keys()]
)

# assert no warning using every opcode except selfdestruct
with warnings.catch_warnings():
warnings.simplefilter("error")

run_computation(
setup_vm(ShanghaiVM),
CANONICAL_ADDRESS_B,
code=code_without_self_destruct,
)

# assert warning with just selfdestruct opcode
with pytest.warns(DeprecationWarning):
run_computation(
setup_vm(ShanghaiVM),
CANONICAL_ADDRESS_B,
code=assemble(opcode_values.SELFDESTRUCT),
)

0 comments on commit 9d445ed

Please sign in to comment.