Skip to content

Commit

Permalink
feat: drop istanbul and berlin support (#3843)
Browse files Browse the repository at this point in the history
this commit drops explicit support for the istanbul and berlin hard
forks per the three year rule suggested in VIP 3365

- istanbul hard fork was 2019-12-09, over 4 years ago
- berlin hard fork was 2021-04-15, which should be 3 years ago by the
  time of 0.4.0 release (or if we can release sooner, shortly after)

this commit also changes the nonreentrant key values for cancun (since
`PUSH0` takes 1 less byte in the bytecode).
  • Loading branch information
charles-cooper authored Mar 12, 2024
1 parent 9cfe7b4 commit a9ee641
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 60 deletions.
16 changes: 3 additions & 13 deletions docs/compiling-a-contract.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,20 +173,10 @@ When using the JSON interface, you can include the ``"evmVersion"`` key within t
Target Options
--------------

The following is a list of supported EVM versions, and changes in the compiler introduced with each version. Backward compatibility is not guaranteed between each version.
The following is a list of supported EVM versions, and changes in the compiler introduced with each version. Backward compatibility is not guaranteed between each version. In general, the compiler team maintains an informal policy that the compiler will support 3 years of hard fork rulesets, but this policy may be revisited as appropriate.


.. py:attribute:: istanbul
- The ``CHAINID`` opcode is accessible via ``chain.id``
- The ``SELFBALANCE`` opcode is used for calls to ``self.balance``
- Gas estimates changed for ``SLOAD`` and ``BALANCE``

.. py:attribute:: berlin
- Gas estimates changed for ``EXTCODESIZE``, ``EXTCODECOPY``, ``EXTCODEHASH``, ``SLOAD``, ``SSTORE``, ``CALL``, ``CALLCODE``, ``DELEGATECALL`` and ``STATICCALL``
- Functions marked with ``@nonreentrant`` are protected with different values (3 and 2) than contracts targeting pre-berlin.
- ``BASEFEE`` is accessible via ``block.basefee``
.. py:attribute:: london
.. py:attribute:: paris
Expand Down Expand Up @@ -247,7 +237,7 @@ The following example describes the expected input format of ``vyper-json``. Com
},
// Optional
"settings": {
"evmVersion": "shanghai", // EVM version to compile for. Can be istanbul, berlin, paris, shanghai (default) or cancun (experimental!).
"evmVersion": "shanghai", // EVM version to compile for. Can be london, paris, shanghai (default) or cancun (experimental!).
// optional, optimization mode
// defaults to "gas". can be one of "gas", "codesize", "none",
// false and true (the last two are for backwards compatibility).
Expand Down
5 changes: 1 addition & 4 deletions tests/functional/syntax/test_self_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ def __default__():
"""
settings = Settings(evm_version=evm_version)
opcodes = compiler.compile_code(code, output_formats=["opcodes"], settings=settings)["opcodes"]
if EVM_VERSIONS[evm_version] >= EVM_VERSIONS["istanbul"]:
assert "SELFBALANCE" in opcodes
else:
assert "SELFBALANCE" not in opcodes
assert "SELFBALANCE" in opcodes

c = get_contract_with_gas_estimation(code, evm_version=evm_version)
w3.eth.send_transaction({"to": c.address, "value": 1337})
Expand Down
4 changes: 3 additions & 1 deletion tests/unit/cli/vyper_json/test_get_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ def test_unknown_evm():
"byzantium",
"constantinople",
"petersburg",
"istanbul",
"berlin",
],
)
def test_early_evm(evm_version):
with pytest.raises(JSONError):
get_evm_version({"settings": {"evmVersion": evm_version}})


@pytest.mark.parametrize("evm_version", ["istanbul", "berlin", "paris", "shanghai", "cancun"])
@pytest.mark.parametrize("evm_version", ["london", "paris", "shanghai", "cancun"])
def test_valid_evm(evm_version):
assert evm_version == get_evm_version({"settings": {"evmVersion": evm_version}})
14 changes: 5 additions & 9 deletions tests/unit/compiler/test_opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ def test_version_check(evm_version):
assert opcodes.version_check(begin=evm_version)
assert opcodes.version_check(end=evm_version)
assert opcodes.version_check(begin=evm_version, end=evm_version)
if evm_version not in ("istanbul"):
assert not opcodes.version_check(end="istanbul")
istanbul_check = opcodes.version_check(begin="istanbul")
assert istanbul_check == (opcodes.EVM_VERSIONS[evm_version] >= opcodes.EVM_VERSIONS["istanbul"])
if evm_version not in ("london",):
assert not opcodes.version_check(end="london")
london_check = opcodes.version_check(begin="london")
assert london_check == (opcodes.EVM_VERSIONS[evm_version] >= opcodes.EVM_VERSIONS["london"])


def test_get_opcodes(evm_version):
Expand All @@ -50,11 +50,7 @@ def test_get_opcodes(evm_version):
assert "CHAINID" in ops
assert ops["CREATE2"][-1] == 32000

if evm_version in ("london", "berlin", "paris", "shanghai", "cancun"):
assert ops["SLOAD"][-1] == 2100
else:
assert evm_version == "istanbul"
assert ops["SLOAD"][-1] == 800
assert ops["SLOAD"][-1] == 2100

if evm_version in ("shanghai", "cancun"):
assert "PUSH0" in ops
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/compiler/test_pre_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ def test():

def test_evm_version_check(assert_compile_failed):
code = """
#pragma evm-version berlin
#pragma evm-version london
"""
assert compile_code(code, settings=Settings(evm_version=None)) is not None
assert compile_code(code, settings=Settings(evm_version="berlin")) is not None
assert compile_code(code, settings=Settings(evm_version="london")) is not None
# should fail if compile options indicate different evm version
# from source pragma
with pytest.raises(StructureException):
Expand Down
4 changes: 3 additions & 1 deletion vyper/cli/vyper_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,10 @@ def get_evm_version(input_dict: dict) -> Optional[str]:
"spuriousDragon",
"byzantium",
"constantinople",
"istanbul",
"berlin",
):
raise JSONError("Vyper does not support pre-istanbul EVM versions")
raise JSONError("Vyper does not support pre-london EVM versions")
if evm_version not in EVM_VERSIONS:
raise JSONError(f"Unknown EVM version - '{evm_version}'")

Expand Down
11 changes: 1 addition & 10 deletions vyper/codegen/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
from vyper.exceptions import (
CodegenPanic,
CompilerPanic,
EvmVersionException,
StructureException,
TypeCheckFailure,
TypeMismatch,
Expand Down Expand Up @@ -222,11 +221,7 @@ def parse_Attribute(self):
if self.expr.attr == "balance":
addr = Expr.parse_value_expr(self.expr.value, self.context)
if addr.typ == AddressT():
if (
isinstance(self.expr.value, vy_ast.Name)
and self.expr.value.id == "self"
and version_check(begin="istanbul")
):
if isinstance(self.expr.value, vy_ast.Name) and self.expr.value.id == "self":
seq = ["selfbalance"]
else:
seq = ["balance", addr]
Expand Down Expand Up @@ -302,10 +297,6 @@ def parse_Attribute(self):
elif key == "tx.gasprice":
return IRnode.from_list(["gasprice"], typ=UINT256_T)
elif key == "chain.id":
if not version_check(begin="istanbul"):
raise EvmVersionException(
"chain.id is unavailable prior to istanbul ruleset", self.expr
)
return IRnode.from_list(["chainid"], typ=UINT256_T)

# Other variables
Expand Down
10 changes: 5 additions & 5 deletions vyper/codegen/function_definitions/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,14 @@ def get_nonreentrant_lock(func_t):
LOAD, STORE = "sload", "sstore"
if version_check(begin="cancun"):
LOAD, STORE = "tload", "tstore"

if version_check(begin="berlin"):
# any nonzero values would work here (see pricing as of net gas
# for tload/tstore we don't need to care about net gas metering,
# choose small constants (e.g. 0 can be replaced by PUSH0)
final_value, temp_value = 0, 1
else:
# any nonzero values can work here (see pricing as of net gas
# metering); these values are chosen so that downgrading to the
# 0,1 scheme (if it is somehow necessary) is safe.
final_value, temp_value = 3, 2
else:
final_value, temp_value = 0, 1

check_notset = ["assert", ["ne", temp_value, [LOAD, nkey]]]

Expand Down
30 changes: 15 additions & 15 deletions vyper/evm/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
# 1. Fork rules go from oldest (lowest value) to newest (highest value).
# 2. Fork versions aren't actually tied to anything. They are not a part of our
# official API. *DO NOT USE THE VALUES FOR ANYTHING IMPORTANT* besides versioning.
# 3. Per VIP-3365, we support mainnet fork choice rules up to 1 year old
# 3. Per VIP-3365, we support mainnet fork choice rules up to 3 years old
# (and may optionally have forward support for experimental/unreleased
# fork choice rules)
_evm_versions = ("istanbul", "berlin", "london", "paris", "shanghai", "cancun")
_evm_versions = ("london", "paris", "shanghai", "cancun")
EVM_VERSIONS: dict[str, int] = dict((v, i) for i, v in enumerate(_evm_versions))


Expand All @@ -22,7 +22,7 @@
# opcode as hex value
# number of values removed from stack
# number of values added to stack
# gas cost (istanbul, berlin, paris, shanghai, cancun)
# gas cost (london, paris, shanghai, cancun)
OPCODES: OpcodeMap = {
"STOP": (0x00, 0, 0, 0),
"ADD": (0x01, 2, 1, 3),
Expand Down Expand Up @@ -62,11 +62,11 @@
"CODESIZE": (0x38, 0, 1, 2),
"CODECOPY": (0x39, 3, 0, 3),
"GASPRICE": (0x3A, 0, 1, 2),
"EXTCODESIZE": (0x3B, 1, 1, (700, 2600)),
"EXTCODECOPY": (0x3C, 4, 0, (700, 2600)),
"EXTCODESIZE": (0x3B, 1, 1, 2600),
"EXTCODECOPY": (0x3C, 4, 0, 2600),
"RETURNDATASIZE": (0x3D, 0, 1, 2),
"RETURNDATACOPY": (0x3E, 3, 0, 3),
"EXTCODEHASH": (0x3F, 1, 1, (700, 2600)),
"EXTCODEHASH": (0x3F, 1, 1, 2600),
"BLOCKHASH": (0x40, 1, 1, 20),
"COINBASE": (0x41, 0, 1, 2),
"TIMESTAMP": (0x42, 0, 1, 2),
Expand All @@ -76,20 +76,20 @@
"GASLIMIT": (0x45, 0, 1, 2),
"CHAINID": (0x46, 0, 1, 2),
"SELFBALANCE": (0x47, 0, 1, 5),
"BASEFEE": (0x48, 0, 1, (None, 2)),
"BASEFEE": (0x48, 0, 1, 2),
"POP": (0x50, 1, 0, 2),
"MLOAD": (0x51, 1, 1, 3),
"MSTORE": (0x52, 2, 0, 3),
"MSTORE8": (0x53, 2, 0, 3),
"SLOAD": (0x54, 1, 1, (800, 2100)),
"SLOAD": (0x54, 1, 1, 2100),
"SSTORE": (0x55, 2, 0, 20000),
"JUMP": (0x56, 1, 0, 8),
"JUMPI": (0x57, 2, 0, 10),
"PC": (0x58, 0, 1, 2),
"MSIZE": (0x59, 0, 1, 2),
"GAS": (0x5A, 0, 1, 2),
"JUMPDEST": (0x5B, 0, 0, 1),
"MCOPY": (0x5E, 3, 0, (None, None, None, None, None, 3)),
"MCOPY": (0x5E, 3, 0, (None, None, None, 3)),
"PUSH0": (0x5F, 0, 1, 2),
"PUSH1": (0x60, 0, 1, 3),
"PUSH2": (0x61, 0, 1, 3),
Expand Down Expand Up @@ -161,19 +161,19 @@
"LOG3": (0xA3, 5, 0, 1500),
"LOG4": (0xA4, 6, 0, 1875),
"CREATE": (0xF0, 3, 1, 32000),
"CALL": (0xF1, 7, 1, (700, 2100)),
"CALLCODE": (0xF2, 7, 1, (700, 2100)),
"CALL": (0xF1, 7, 1, 2100),
"CALLCODE": (0xF2, 7, 1, 2100),
"RETURN": (0xF3, 2, 0, 0),
"DELEGATECALL": (0xF4, 6, 1, (700, 2100)),
"DELEGATECALL": (0xF4, 6, 1, 2100),
"CREATE2": (0xF5, 4, 1, 32000),
"SELFDESTRUCT": (0xFF, 1, 0, 25000),
"STATICCALL": (0xFA, 6, 1, (700, 2100)),
"STATICCALL": (0xFA, 6, 1, 2100),
"REVERT": (0xFD, 2, 0, 0),
"INVALID": (0xFE, 0, 0, 0),
"DEBUG": (0xA5, 1, 0, 0),
"BREAKPOINT": (0xA6, 0, 0, 0),
"TLOAD": (0x5C, 1, 1, (None, None, None, None, None, 100)),
"TSTORE": (0x5D, 2, 0, (None, None, None, None, None, 100)),
"TLOAD": (0x5C, 1, 1, (None, None, None, 100)),
"TSTORE": (0x5D, 2, 0, (None, None, None, 100)),
}

PSEUDO_OPCODES: OpcodeMap = {
Expand Down

0 comments on commit a9ee641

Please sign in to comment.