Skip to content

test_worst_shifts()

Documentation for tests/benchmark/test_worst_compute.py::test_worst_shifts@88e9fb8f.

Generate fixtures for these test cases for Osaka with:

fill -v tests/benchmark/test_worst_compute.py::test_worst_shifts -m benchmark

Test running a block with as many shift instructions with non-trivial arguments. This test generates left-right pairs of shifts to avoid zeroing the argument. The shift amounts are randomly pre-selected from the constant pool of 15 values on the stack.

Source code in tests/benchmark/test_worst_compute.py
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
@pytest.mark.parametrize("shift_right", [Op.SHR, Op.SAR])
def test_worst_shifts(
    benchmark_test: BenchmarkTestFiller,
    pre: Alloc,
    fork: Fork,
    shift_right: Op,
    gas_benchmark_value: int,
) -> None:
    """
    Test running a block with as many shift instructions with non-trivial
    arguments. This test generates left-right pairs of shifts to avoid zeroing
    the argument. The shift amounts are randomly pre-selected from the constant
    pool of 15 values on the stack.
    """
    max_code_size = fork.max_code_size()

    def to_signed(x: int) -> int:
        return x if x < 2**255 else x - 2**256

    def to_unsigned(x: int) -> int:
        return x if x >= 0 else x + 2**256

    def shr(x: int, s: int) -> int:
        return x >> s

    def shl(x: int, s: int) -> int:
        return x << s

    def sar(x: int, s: int) -> int:
        return to_unsigned(to_signed(x) >> s)

    match shift_right:
        case Op.SHR:
            shift_right_fn = shr
        case Op.SAR:
            shift_right_fn = sar
        case _:
            raise ValueError(f"Unexpected shift op: {shift_right}")

    rng = random.Random(1)  # Use random with a fixed seed.
    initial_value = 2**256 - 1  # The initial value to be shifted; should be
    # negative for SAR.

    # Create the list of shift amounts with 15 elements (max reachable by DUPs
    # instructions). For the worst case keep the values small and omit values
    # divisible by 8.
    shift_amounts = [x + (x >= 8) + (x >= 15) for x in range(1, 16)]

    code_prefix = sum(Op.PUSH1[sh] for sh in shift_amounts) + Op.JUMPDEST + Op.CALLDATALOAD(0)
    code_suffix = Op.POP + Op.JUMP(len(shift_amounts) * 2)
    code_body_len = max_code_size - len(code_prefix) - len(code_suffix)

    def select_shift_amount(shift_fn: Any, v: Any) -> Any:
        """Select a shift amount that will produce a non-zero result."""
        while True:
            index = rng.randint(0, len(shift_amounts) - 1)
            sh = shift_amounts[index]
            new_v = shift_fn(v, sh) % 2**256
            if new_v != 0:
                return new_v, index

    code_body = Bytecode()
    v = initial_value
    while len(code_body) <= code_body_len - 4:
        v, i = select_shift_amount(shl, v)
        code_body += make_dup(len(shift_amounts) - i) + Op.SHL
        v, i = select_shift_amount(shift_right_fn, v)
        code_body += make_dup(len(shift_amounts) - i) + shift_right

    code = code_prefix + code_body + code_suffix
    assert len(code) == max_code_size - 2

    tx = Transaction(
        to=pre.deploy_contract(code=code),
        data=initial_value.to_bytes(32, byteorder="big"),
        gas_limit=gas_benchmark_value,
        sender=pre.fund_eoa(),
    )

    benchmark_test(tx=tx)

Parametrized Test Cases

This test case is only parametrized by fork.

Test ID (Abbreviated) shift_right
...fork_Prague-blockchain_test-shift_right_SHR SHR
...fork_Prague-blockchain_test-shift_right_SAR SAR
...fork_Osaka-blockchain_test-shift_right_SHR SHR
...fork_Osaka-blockchain_test-shift_right_SAR SAR