Skip to content

Commit

Permalink
Merge pull request #53 from jsign/jsign-7709
Browse files Browse the repository at this point in the history
verkle: add eip-7709 test
  • Loading branch information
jsign authored Sep 25, 2024
2 parents 7ea89a9 + 35c79c8 commit 5694e15
Showing 1 changed file with 73 additions and 34 deletions.
107 changes: 73 additions & 34 deletions tests/verkle/eip7709_blockhash_witness/test_blockhash_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,72 +19,104 @@
Transaction,
WitnessCheck,
)
from ethereum_test_types.verkle.helpers import Hash, chunkify_code
from ethereum_test_tools.vm.opcode import Opcodes as Op

REFERENCE_SPEC_GIT_PATH = "EIPS/eip-7709.md"
REFERENCE_SPEC_VERSION = "TODO"

# TODO(verkle): fix
blockhash_system_contract_address = Address("0xa4690f0ed0d089faa1e0ad94c8f1b4a2fd4b0734")
HISTORY_STORAGE_ADDRESS = 8192
BLOCKHASH_OLD_WINDOW = 256
block_number = 1000
system_contract_address = Address("0xfffffffffffffffffffffffffffffffffffffffe")
HISTORY_SERVE_WINDOW = 8192
BLOCKHASH_SERVE_WINDOW = 256
block_number = BLOCKHASH_SERVE_WINDOW + 5


@pytest.mark.valid_from("Verkle")
@pytest.mark.skip(reason="Not fully implemented")
@pytest.mark.parametrize(
"block_num_target",
"blocknum_target",
[
block_number + 10,
block_number + 1,
block_number,
block_number - 1,
block_number - BLOCKHASH_OLD_WINDOW,
block_number - BLOCKHASH_OLD_WINDOW - 1,
block_number - 2,
block_number - BLOCKHASH_SERVE_WINDOW,
block_number - BLOCKHASH_SERVE_WINDOW - 1,
],
ids=[
"future_block",
"current_block",
"previous_block",
"previous_block", # Note this block is also written by EIP-2935
"previous_previous_block",
"last_supported_block",
"too_old_block",
],
)
def test_blockhash(blockchain_test: BlockchainTestFiller, block_num_target: int):
def test_blockhash(blockchain_test: BlockchainTestFiller, blocknum_target: int):
"""
Test BLOCKHASH witness.
"""
_blockhash(blockchain_test, block_num_target)
# TODO(verkle): Today the only way to create these assertions is by hardcoding the values.
# If in the future the testing library can calculate these upfront, we should
# calculate them instead of hardcoding them.
hardcoded_blockhashes = {
block_number - 2: Hash(0x127986F98B6BAB3B2AF5AC250912018D9982696E7B9B364D28190FA68C0AB49D),
block_number
- BLOCKHASH_SERVE_WINDOW: Hash(
0xBBB791529CE751AC1FDC021C21B0A7F13A22905BD5BB396EC3F57EBF97C0A14D
),
}
_blockhash(blockchain_test, blocknum_target, hardcoded_blockhashes)


@pytest.mark.valid_from("Verkle")
def test_blockhash_warm(blockchain_test: BlockchainTestFiller):
"""
Test BLOCKHASH witness with warm cost.
"""
# TODO(verkle): Today the only way to create these assertions is by hardcoding the values.
# If in the future the testing library can calculate these upfront, we should
# calculate them instead of hardcoding them.
hardcoded_blockhashes = {
block_number - 2: Hash(0x1B027321A3F7FE2F073F9B9C654CF3E62ABD2A8324A198FD7C46D056BC3CE976),
}
_blockhash(blockchain_test, block_number - 2, hardcoded_blockhashes, warm=True)


@pytest.mark.valid_from("Verkle")
@pytest.mark.skip(reason="Not fully implemented")
def test_blockhash_insufficient_gas(blockchain_test: BlockchainTestFiller):
"""
Test BLOCKHASH with insufficient gas.
Test BLOCKHASH with insufficient gas for witness addition.
"""
_blockhash(blockchain_test, block_number - 1, gas_limit=21_042, fail=True)
# 21_223 = 21_000 + (one code-chunk) 200 + (PUSH2) 3 + (BLOCKHASH constant cost) 20
_blockhash(blockchain_test, block_number - 2, {}, gas_limit=21_223, fail=True)


def _blockhash(
blockchain_test: BlockchainTestFiller,
block_num_target: int,
blocknum_target: int,
hardcoded_blockhashes: dict[int, Hash],
gas_limit: int = 1_000_000,
warm: bool = False,
fail: bool = False,
):
env = Environment(
fee_recipient="0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
difficulty=0x20000,
gas_limit=10000000000,
number=1,
number=0,
timestamp=1000,
)

pre = {
TestAddress: Account(balance=1000000000000000000000),
TestAddress2: Account(code=Op.BLOCKHASH(block_num_target)),
TestAddress2: Account(code=Op.BLOCKHASH(blocknum_target) * (2 if warm else 1)),
}

# Create block_number-1 empty blocks to fill the ring buffer.
blocks: list[Block] = []
for b in range(block_number - 1):
blocks.append(Block())

tx = Transaction(
ty=0x0,
chain_id=0x01,
Expand All @@ -96,26 +128,33 @@ def _blockhash(

witness_check = WitnessCheck(fork=Verkle)
for address in [env.fee_recipient, TestAddress, TestAddress2]:
witness_check.add_account_full(
address=address,
account=(None if address == env.fee_recipient else pre[address]),
witness_check.add_account_full(address=address, account=pre.get(address))
code_chunks = chunkify_code(pre[TestAddress2].code)
for i, chunk in enumerate(code_chunks, start=0):
witness_check.add_code_chunk(address=TestAddress2, chunk_number=i, value=chunk)

# TODO(verkle): when system contract exhaustive checks are supported in
# the testing library, add here the 2935 actions on the witness too.

# If the execution isn't expected to fail due to insufficient gas, and we satisfy the
# block number target condition defined in the spec, we should assert the appropriate slot
# is in the witness.
if not fail and not (
blocknum_target >= block_number or blocknum_target + BLOCKHASH_SERVE_WINDOW < block_number
):
witness_check.add_storage_slot(
system_contract_address,
blocknum_target % HISTORY_SERVE_WINDOW,
hardcoded_blockhashes.get(blocknum_target),
)
# TODO: Add this back once we update the test to include 1000+ dummy blocks
# if fail:
# storage_slot = block_num_target % HISTORY_STORAGE_ADDRESS
# value = None # TODO: Process the null value
# witness_check.add_storage_slot(
# address=blockhash_system_contract_address,
# storage_slot=storage_slot,
# value=value,
# )

blocks = [

# The last block contains a single transaction with the BLOCKHASH instruction(s).
blocks.append(
Block(
txs=[tx],
witness_check=witness_check,
)
]
)

blockchain_test(
genesis_environment=env,
Expand Down

0 comments on commit 5694e15

Please sign in to comment.