Skip to content

Commit

Permalink
witness: exhaustive check fixes (#876)
Browse files Browse the repository at this point in the history
* skip temporarily test

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: call tests fixes

Signed-off-by: Ignacio Hagopian <[email protected]>

* uncomment

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: fix codecopy tests

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: contract execution test fix

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: value bearing CALL with non existent account fixes

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: extcodesize test fixes

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: coinbase test fix

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: balance instruction test fixes

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: 2935-contract execution fixes

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: extcodesize insufficient gas fixes

Signed-off-by: Ignacio Hagopian <[email protected]>

* eip4762: create with big calldata test fixes

Signed-off-by: Ignacio Hagopian <[email protected]>

---------

Signed-off-by: Ignacio Hagopian <[email protected]>
  • Loading branch information
jsign authored Oct 7, 2024
1 parent 78b004b commit de2bb1e
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 46 deletions.
27 changes: 22 additions & 5 deletions tests/verkle/eip4762_verkle_gas_witness/test_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,27 @@ def test_balance(blockchain_test: BlockchainTestFiller, fork: Fork, target, warm


@pytest.mark.valid_from("Verkle")
@pytest.mark.parametrize("target", [example_address, precompile_address])
def test_balance_insufficient_gas(blockchain_test: BlockchainTestFiller, fork: Fork, target):
@pytest.mark.parametrize(
"target",
[
example_address,
precompile_address,
],
)
@pytest.mark.parametrize(
" gas, exp_target_basic_data",
[
(21_203 + 2099, False),
(21_203 + 2100, True),
],
)
def test_balance_insufficient_gas(
blockchain_test: BlockchainTestFiller, fork: Fork, target, gas, exp_target_basic_data
):
"""
Test BALANCE with insufficient gas.
"""
_balance(blockchain_test, fork, target, False, 21_042)
_balance(blockchain_test, fork, target, exp_target_basic_data, gas, fails=True)


def _balance(
Expand All @@ -64,6 +79,7 @@ def _balance(
exp_target_basic_data: bool,
gas_limit=1_000_000,
warm=False,
fails=False,
):
env = Environment(
fee_recipient="0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
Expand Down Expand Up @@ -98,8 +114,6 @@ def _balance(
for i, chunk in enumerate(code_chunks, start=0):
witness_check.add_code_chunk(address=TestAddress2, chunk_number=i, value=chunk)

witness_check.add_storage_slot(address=TestAddress2, storage_slot=0, value=None)

target_account = (
pre[target]
if target != system_contract_address
Expand All @@ -109,6 +123,9 @@ def _balance(
if exp_target_basic_data:
witness_check.add_account_basic_data(address=target, account=target_account)

if not fails:
witness_check.add_storage_slot(address=TestAddress2, storage_slot=0, value=None)

blocks = [
Block(
txs=[tx],
Expand Down
26 changes: 16 additions & 10 deletions tests/verkle/eip4762_verkle_gas_witness/test_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def test_calls_warm(blockchain_test: BlockchainTestFiller, fork: Fork, call_inst


@pytest.mark.valid_from("Verkle")
@pytest.mark.skip("Adjust parameters")
@pytest.mark.parametrize(
"call_instruction, value_bearing, gas_limit, enough_gas_call_target",
[
Expand Down Expand Up @@ -154,10 +155,10 @@ def _generic_call(

if call_instruction == Op.CALL or call_instruction == Op.CALLCODE:
tx_value = 0
caller_code = call_instruction(1_000, target, value, 0, 0, 0, 32)
caller_code = call_instruction(10_000, target, value, 0, 0, 0, 32)
if call_instruction == Op.DELEGATECALL or call_instruction == Op.STATICCALL:
tx_value = value
caller_code = call_instruction(1_000, target, 0, 0, 0, 32)
caller_code = call_instruction(10_000, target, 0, 0, 0, 32)

pre = {
TestAddress: Account(balance=1000000000000000000000),
Expand Down Expand Up @@ -186,7 +187,9 @@ def _generic_call(
for address in [TestAddress, caller_address, env.fee_recipient]:
witness_check.add_account_full(address=address, account=pre.get(address))
if enough_gas_call_target:
if value > 0 or (target != precompile_address and target != precompile_address):
if target != precompile_address and target != system_contract_address:
witness_check.add_account_basic_data(address=target, account=target_account)
if call_instruction == Op.CALL and value > 0:
witness_check.add_account_basic_data(address=target, account=target_account)

code_chunks = chunkify_code(pre[caller_address].code)
Expand All @@ -200,7 +203,11 @@ def _generic_call(
if target == system_contract_address:
# If the target is the 2935 system contract, we should check for the first storage-slot.
# The account storage address depends on the kind of *CALL done.
sslot_target = system_contract_address if call_instruction == Op.CALL else caller_address
sslot_target = (
system_contract_address
if (call_instruction == Op.CALL or call_instruction == Op.STATICCALL)
else caller_address
)
witness_check.add_storage_slot(address=sslot_target, storage_slot=0, value=None)

blocks = [
Expand Down Expand Up @@ -235,9 +242,7 @@ def _generic_call(
"call_instruction, gas_limit, enough_gas_account_creation",
[
(Op.CALL, 100000000, True),
(Op.CALL, 21_042, False),
(Op.CALLCODE, 100000000, True),
(Op.CALLCODE, 21_042, False),
# (Op.CALL, 62_000, False), # TODO(verkle): fix this
],
)
def test_call_non_existent_account(
Expand All @@ -247,7 +252,7 @@ def test_call_non_existent_account(
enough_gas_account_creation: bool,
):
"""
Test *CALL witness assertion when target account does not exist.
Test value-bearing *CALL witness assertion when target account does not exist.
"""
env = Environment(
fee_recipient="0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
Expand All @@ -263,7 +268,7 @@ def test_call_non_existent_account(
TestAddress: Account(balance=1000000000000000000000),
caller_address: Account(
balance=2000000000000000000000,
code=call_instruction(1_000, TestAddress2, call_value, 0, 0, 0, 32),
code=call_instruction(100000000, TestAddress2, call_value, 0, 0, 0, 32),
),
}

Expand All @@ -284,8 +289,9 @@ def test_call_non_existent_account(
for i, chunk in enumerate(code_chunks, start=0):
witness_check.add_code_chunk(address=caller_address, chunk_number=i, value=chunk)

witness_check.add_account_basic_data(address=TestAddress2, account=None)
if enough_gas_account_creation:
witness_check.add_account_full(address=TestAddress2, account=None)
witness_check.add_account_codehash(address=TestAddress2, codehash=None)

blocks = [
Block(
Expand Down
16 changes: 5 additions & 11 deletions tests/verkle/eip4762_verkle_gas_witness/test_codecopy_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,14 @@
"partial_out_of_bounds_touching_further_non_existent_code_chunk",
],
)
def test_generic_codecopy(
blockchain_test: BlockchainTestFiller, instruction, offset, size
):
def test_generic_codecopy(blockchain_test: BlockchainTestFiller, instruction, offset, size):
"""
Test *CODECOPY witness.
"""
start = offset if offset < code_size else code_size
end = offset + size if offset + size < code_size else code_size
end = offset + size - 1 if offset + size < code_size else code_size - 1
witness_code_chunks = range(0, 0)
if start < code_size and start != end:
if start < code_size:
start_chunk = start // 31
end_chunk = end // 31
witness_code_chunks = range(start_chunk, end_chunk + 1)
Expand Down Expand Up @@ -205,9 +203,7 @@ def _generic_codecopy(
extcodecopy_code = Op.EXTCODECOPY(TestAddress2, 0, offset, size) * repeat
pre = {
TestAddress: Account(balance=1000000000000000000000),
TestAddress2: Account(
code=codecopy_code + Op.PUSH0 * (code_size - len(codecopy_code))
),
TestAddress2: Account(code=codecopy_code + Op.PUSH0 * (code_size - len(codecopy_code))),
dummy_address: Account(code=extcodecopy_code),
}

Expand Down Expand Up @@ -241,9 +237,7 @@ def _generic_codecopy(
witness_check.add_code_chunk(to, i, code_chunks[i])

if instr == Op.EXTCODECOPY:
witness_check.add_account_basic_data(
address=TestAddress2, account=pre.get(TestAddress2)
)
witness_check.add_account_basic_data(address=TestAddress2, account=pre.get(TestAddress2))

# Depending on the CODECOPY/EXTCODECOPY offset and size, we include the extra expected
# code-chunks.
Expand Down
11 changes: 9 additions & 2 deletions tests/verkle/eip4762_verkle_gas_witness/test_coinbase_fees.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@


@pytest.mark.valid_from("Verkle")
@pytest.mark.parametrize("priority_fee", [0, 100])
@pytest.mark.parametrize(
"priority_fee",
[
0,
100,
],
)
def test_coinbase_fees(blockchain_test: BlockchainTestFiller, priority_fee):
"""
Test coinbase witness.
Expand All @@ -48,7 +54,8 @@ def test_coinbase_fees(blockchain_test: BlockchainTestFiller, priority_fee):
to=TestAddress2,
value=100,
gas_limit=1_000_000,
gas_price=priority_fee,
max_fee_per_gas=1_000,
max_priority_fee_per_gas=priority_fee,
)

# TODO(verkle): change value when filling
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def code_with_jumps(size, jumps: list[Jump | Jumpi] = []):
),
( # pushn_with_data_in_chunk_that_cant_be_paid
Op.PUSH0 * 30 + Op.PUSH1(42),
21000,
21_263,
[[0, 0]],
),
( # jump_to_jumpdest_in_pushn_data
Expand Down Expand Up @@ -286,7 +286,7 @@ def test_contract_execution_2935_contract(blockchain_test: BlockchainTestFiller,
addr = Address("0xfffffffffffffffffffffffffffffffffffffffe")
pre = {
TestAddress: Account(balance=1000000000000000000000),
TestAddress2: Account(code=Op.PUSH1(0) + Op.CALL(1_000, addr, 0, 0, 0, 0, 32)),
TestAddress2: Account(code=Op.PUSH1(0) + Op.CALL(100_000, addr, 0, 0, 0, 0, 32)),
}
tx = Transaction(
ty=0x0,
Expand All @@ -308,7 +308,6 @@ def test_contract_execution_2935_contract(blockchain_test: BlockchainTestFiller,

# TestAddress2 CALL to 2935 contract
system_contract_account = Account(**fork.pre_allocation_blockchain()[addr])
witness_check.add_account_basic_data(address=addr, account=system_contract_account)
# A successful execution of the 2935 contract would only include the first two code-chunks.
code_chunks = chunkify_code(system_contract_account.code)
witness_check.add_code_chunk(address=addr, chunk_number=0, value=code_chunks[0])
Expand Down
7 changes: 5 additions & 2 deletions tests/verkle/eip4762_verkle_gas_witness/test_creates.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def test_create(blockchain_test: BlockchainTestFiller, create_instruction: Opcod


@pytest.mark.valid_from("Verkle")
@pytest.mark.skip("TBD when exhaustive check PR gets merged")
@pytest.mark.parametrize(
"create_instruction",
[
Expand Down Expand Up @@ -205,7 +206,7 @@ def test_create_big_calldata(
Test *CREATE checking that code-chunk touching in the witness is not calculated from calldata
size but actual returned code from initcode execution.
"""
contract_code = bytes(Op.PUSH0 * (1000 * 31 + 42))
contract_code = bytes(Op.PUSH0 * (10 * 31 + 42))
_create(
blockchain_test,
create_instruction,
Expand Down Expand Up @@ -296,7 +297,9 @@ def _create(
# - Otherwise, it should prove there's no collision.
witness_check.add_account_full(contract_address, pre.get(contract_address))
# Assert the code-chunks where the contract is deployed are provided
if not generate_collision:
# DO NOT include the code-chunks if there was a collision, or we're testing that
# code-chunk inclusion isn't based on calldata size (see big_calldata test).
if not generate_collision and not initcode_stop_prefix:
code_chunks = chunkify_code(bytes(deploy_code.deploy_code))
for i, chunk in enumerate(code_chunks, start=0):
witness_check.add_code_chunk(address=contract_address, chunk_number=i, value=None)
Expand Down
41 changes: 28 additions & 13 deletions tests/verkle/eip4762_verkle_gas_witness/test_extcodesize.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,31 @@ def test_extcodesize(blockchain_test: BlockchainTestFiller, target, bytecode, fo


@pytest.mark.valid_from("Verkle")
def test_extcodesize_insufficient_gas(blockchain_test: BlockchainTestFiller):
@pytest.mark.parametrize(
"gas, enough_gas_basicdata",
[
(21_203 + 2099, False),
(21_203 + 2100, True),
],
)
def test_extcodesize_insufficient_gas(
blockchain_test: BlockchainTestFiller, gas, enough_gas_basicdata
):
"""
Test EXTCODESIZE with insufficient gas.
Test EXTCODESIZE with insufficient gas for witness.
"""
bytecode = Op.PUSH0 * 10
witness = WitnessCheck(fork=Verkle)
if enough_gas_basicdata:
account = Account(code=bytecode)
witness.add_account_basic_data(address=TestAddress2, account=account)

_extcodesize(
blockchain_test,
TestAddress2,
Op.PUSH0 * 1000,
WitnessCheck(fork=Verkle),
gas_limit=53_540,
bytecode,
witness,
gas_limit=gas,
fails=True,
)

Expand All @@ -101,7 +116,6 @@ def _extcodesize(
gas_limit=1_000_000,
warm=False,
fails=False,
fork: Fork = Verkle,
):

env = Environment(
Expand All @@ -111,9 +125,10 @@ def _extcodesize(
number=1,
timestamp=1000,
)
caller_addr = Address("0xffff19589531694250d570040a0c4b74576919b8")
pre = {
TestAddress: Account(balance=1000000000000000000000),
TestAddress2: Account(
caller_addr: Account(
code=Op.EXTCODESIZE(target) * (2 if warm else 1) + Op.PUSH0 + Op.SSTORE
),
}
Expand All @@ -124,26 +139,26 @@ def _extcodesize(
ty=0x0,
chain_id=0x01,
nonce=0,
to=TestAddress2,
to=caller_addr,
gas_limit=gas_limit,
gas_price=10,
)

post = {}
if not fails:
post[TestAddress2] = Account(code=pre[TestAddress2].code, storage={0: 0x424242})
post[caller_addr] = Account(code=pre[caller_addr].code, storage={0: 0x424242})

witness_check = witness_check_extra
witness_check.add_account_full(env.fee_recipient, None)
witness_check.add_account_full(TestAddress, pre[TestAddress])
witness_check.add_account_full(TestAddress2, pre[TestAddress2])
witness_check.add_account_full(caller_addr, pre[caller_addr])

code_chunks = chunkify_code(pre[TestAddress2].code)
code_chunks = chunkify_code(pre[caller_addr].code)
for i, chunk in enumerate(code_chunks, start=0):
witness_check.add_code_chunk(address=TestAddress2, chunk_number=i, value=chunk)
witness_check.add_code_chunk(address=caller_addr, chunk_number=i, value=chunk)

if not fails:
witness_check.add_storage_slot(address=TestAddress2, storage_slot=0, value=None)
witness_check.add_storage_slot(address=caller_addr, storage_slot=0, value=None)

blocks = [
Block(
Expand Down

0 comments on commit de2bb1e

Please sign in to comment.