Skip to content

test_sstore_bloated()

Documentation for tests/benchmark/stateful/bloatnet/test_single_opcode.py::test_sstore_bloated@21507778.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/benchmark/stateful/bloatnet/test_single_opcode.py::test_sstore_bloated --gas-benchmark-values 1

Benchmark SSTORE opcodes targeting an EOA with storage bloated.

The storage is assumed to be filled from 0-N linearly, where each slot has the value of the key. Except slot 0, this is the pointer to the next free (empty) storage slot.

For this test to work correctly under all parameters then above has to be true. If this is not the case then some tests will not test what they claim to do. For instance, for write_new_value set to False we need to know the current value of the slots.

Source code in tests/benchmark/stateful/bloatnet/test_single_opcode.py
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
@pytest.mark.repricing
@pytest.mark.stub_parametrize("token_name", "bloated_eoa_")
@pytest.mark.parametrize("write_new_value", [False, True])
@pytest.mark.parametrize("existing_slots", [True, False])
@pytest.mark.parametrize("cache_strategy", list(CacheStrategy))
def test_sstore_bloated(
    benchmark_test: BenchmarkTestFiller,
    pre: Alloc,
    fork: Fork,
    gas_benchmark_value: int,
    tx_gas_limit: int,
    token_name: str,
    write_new_value: bool,
    existing_slots: bool,
    cache_strategy: CacheStrategy,
) -> None:
    """
    Benchmark SSTORE opcodes targeting an EOA with storage bloated.

    The storage is assumed to be filled from 0-N linearly, where
    each slot has the value of the key. Except slot 0, this is the
    pointer to the next free (empty) storage slot.

    For this test to work correctly under all parameters then above
    has to be true. If this is not the case then some tests will not
    test what they claim to do. For instance, for `write_new_value`
    set to False we need to know the current value of the slots.
    """
    setup = (
        Op.PUSH0  # [0]
        + Op.SLOAD  # [key], s[0] = key
        + Op.DUP1  # [key, key]
    )

    if write_new_value:
        setup += (
            Op.PUSH1(1)  # [1, key, key]
            + Op.ADD  # [key+1, key]
            + Op.SWAP1  # [key, key+1]
        )

    # After setup phase, the stack element represents
    # [slot, value], slot to write and value to write

    cache_op = Bytecode()
    if cache_strategy == CacheStrategy.CACHE_TX:
        cache_op = (
            Op.DUP1  # [slot, slot, value]
            + Op.SLOAD  # [s[slot], slot, value]
            + Op.POP  # [slot, value]
        )

    # The cache mechanism touches the slot before SSTORE

    runtime_code = (
        setup
        + While(
            body=(
                cache_op  # [slot, value]
                + Op.DUP2  # [value, slot, value]
                + Op.DUP2  # [slot, value, slot, value]
                + Op.SSTORE  # [slot, value], s[slot] = value
                + Op.PUSH1(1)  # [1, slot, value]
                + Op.ADD  # [slot+1, value]
                + Op.SWAP1  # [value, slot+1]
                + Op.PUSH1(1)  # [1, value, slot+1]
                + Op.ADD  # [value+1, slot+1]
                + Op.SWAP1  # [slot+1, value+1]
            ),
            condition=Op.GT(Op.GAS, 0xFFFF),
        )
        + Op.PUSH0  # [0, slot+1, value+1]
        + Op.SSTORE  # s[0] = slot+1
    )

    run_bloated_eoa_benchmark(
        benchmark_test=benchmark_test,
        pre=pre,
        fork=fork,
        gas_benchmark_value=gas_benchmark_value,
        tx_gas_limit=tx_gas_limit,
        authority=pre.stub_eoa(token_name),
        existing_slots=existing_slots,
        runtime_code=runtime_code,
        cache_strategy=cache_strategy,
    )

Parametrized Test Cases

This test generates 12 parametrized test cases across 3 forks.