|  | 
| 19 | 19 | ) | 
| 20 | 20 | from ethereum_test_vm import Opcode, UndefinedOpcodes | 
| 21 | 21 | from ethereum_test_vm import Opcodes as Op | 
|  | 22 | +from tests.unscheduled.eip7692_eof_v1.eip3540_eof_v1.opcodes import V1_EOF_ONLY_OPCODES | 
|  | 23 | +from tests.unscheduled.eip7692_eof_v1.gas_test import gas_test | 
| 22 | 24 | 
 | 
| 23 | 25 | REFERENCE_SPEC_GIT_PATH = "N/A" | 
| 24 | 26 | REFERENCE_SPEC_VERSION = "N/A" | 
| 25 | 27 | 
 | 
| 26 | 28 | 
 | 
| 27 | 29 | def prepare_stack(opcode: Opcode) -> Bytecode: | 
| 28 | 30 |     """Prepare valid stack for opcode.""" | 
| 29 |  | -    if opcode == Op.CREATE: | 
| 30 |  | -        return Op.MSTORE(0, 0x6001600155) + Op.PUSH1(5) + Op.PUSH1(27) + Op.PUSH1(5) | 
| 31 |  | -    if opcode == Op.CREATE2: | 
| 32 |  | -        return Op.MSTORE(0, 0x6001600155) + Op.PUSH1(1) + Op.PUSH1(5) + Op.PUSH1(27) + Op.PUSH1(5) | 
| 33 | 31 |     if opcode == Op.JUMPI: | 
| 34 |  | -        return Op.PUSH1(1) + Op.PUSH1(5) | 
|  | 32 | +        return Op.PUSH1(1) + Op.PUSH1(3) + Op.PC + Op.ADD | 
| 35 | 33 |     if opcode == Op.JUMP: | 
| 36 |  | -        return Op.PUSH1(3) | 
| 37 |  | -    if opcode == Op.RETURNDATACOPY: | 
| 38 |  | -        return Op.PUSH1(0) * 3 | 
| 39 |  | -    return Op.PUSH1(0x01) * 32 | 
|  | 34 | +        return Op.PUSH1(3) + Op.PC + Op.ADD | 
|  | 35 | +    return Op.PUSH1(0x00) * 32 | 
| 40 | 36 | 
 | 
| 41 | 37 | 
 | 
| 42 | 38 | def prepare_suffix(opcode: Opcode) -> Bytecode: | 
| @@ -122,3 +118,161 @@ def test_cover_revert(state_test: StateTestFiller, pre: Alloc) -> None: | 
| 122 | 118 |     ) | 
| 123 | 119 | 
 | 
| 124 | 120 |     state_test(env=Environment(), pre=pre, post={}, tx=tx) | 
|  | 121 | + | 
|  | 122 | + | 
|  | 123 | +opcode_to_gas = { | 
|  | 124 | +    Op.ADD: 3, | 
|  | 125 | +    Op.MUL: 5, | 
|  | 126 | +    Op.SUB: 3, | 
|  | 127 | +    Op.DIV: 5, | 
|  | 128 | +    Op.SDIV: 5, | 
|  | 129 | +    Op.MOD: 5, | 
|  | 130 | +    Op.SMOD: 5, | 
|  | 131 | +    Op.ADDMOD: 8, | 
|  | 132 | +    Op.MULMOD: 8, | 
|  | 133 | +    Op.EXP: 10, | 
|  | 134 | +    Op.SIGNEXTEND: 5, | 
|  | 135 | +    Op.LT: 3, | 
|  | 136 | +    Op.GT: 3, | 
|  | 137 | +    Op.SLT: 3, | 
|  | 138 | +    Op.SGT: 3, | 
|  | 139 | +    Op.EQ: 3, | 
|  | 140 | +    Op.ISZERO: 3, | 
|  | 141 | +    Op.AND: 3, | 
|  | 142 | +    Op.OR: 3, | 
|  | 143 | +    Op.XOR: 3, | 
|  | 144 | +    Op.NOT: 3, | 
|  | 145 | +    Op.BYTE: 3, | 
|  | 146 | +    Op.SHL: 3, | 
|  | 147 | +    Op.SHR: 3, | 
|  | 148 | +    Op.SAR: 3, | 
|  | 149 | +    Op.CLZ: 5, | 
|  | 150 | +    Op.SHA3: 30, | 
|  | 151 | +    Op.ADDRESS: 2, | 
|  | 152 | +    Op.BALANCE: 100, | 
|  | 153 | +    Op.ORIGIN: 2, | 
|  | 154 | +    Op.CALLER: 2, | 
|  | 155 | +    Op.CALLVALUE: 2, | 
|  | 156 | +    Op.CALLDATALOAD: 3, | 
|  | 157 | +    Op.CALLDATASIZE: 2, | 
|  | 158 | +    Op.CALLDATACOPY: 3, | 
|  | 159 | +    Op.CODESIZE: 2, | 
|  | 160 | +    Op.CODECOPY: 3, | 
|  | 161 | +    Op.GASPRICE: 2, | 
|  | 162 | +    Op.EXTCODESIZE: 100, | 
|  | 163 | +    Op.EXTCODECOPY: 100, | 
|  | 164 | +    Op.RETURNDATASIZE: 2, | 
|  | 165 | +    Op.RETURNDATACOPY: 3, | 
|  | 166 | +    Op.EXTCODEHASH: 100, | 
|  | 167 | +    Op.BLOCKHASH: 20, | 
|  | 168 | +    Op.COINBASE: 2, | 
|  | 169 | +    Op.TIMESTAMP: 2, | 
|  | 170 | +    Op.NUMBER: 2, | 
|  | 171 | +    Op.PREVRANDAO: 2, | 
|  | 172 | +    Op.GASLIMIT: 2, | 
|  | 173 | +    Op.CHAINID: 2, | 
|  | 174 | +    Op.SELFBALANCE: 5, | 
|  | 175 | +    Op.BASEFEE: 2, | 
|  | 176 | +    Op.BLOBHASH: 3, | 
|  | 177 | +    Op.BLOBBASEFEE: 2, | 
|  | 178 | +    Op.POP: 2, | 
|  | 179 | +    Op.MLOAD: 3, | 
|  | 180 | +    Op.MSTORE: 3, | 
|  | 181 | +    Op.MSTORE8: 3, | 
|  | 182 | +    Op.SLOAD: 100, | 
|  | 183 | +    Op.JUMP: 8, | 
|  | 184 | +    Op.JUMPI: 10, | 
|  | 185 | +    Op.PC: 2, | 
|  | 186 | +    Op.MSIZE: 2, | 
|  | 187 | +    Op.GAS: 2, | 
|  | 188 | +    Op.JUMPDEST: 1, | 
|  | 189 | +    Op.TLOAD: 100, | 
|  | 190 | +    Op.TSTORE: 100, | 
|  | 191 | +    Op.MCOPY: 3, | 
|  | 192 | +    Op.PUSH0: 2, | 
|  | 193 | +    Op.LOG0: 375, | 
|  | 194 | +    Op.LOG1: 2 * 375, | 
|  | 195 | +    Op.LOG2: 3 * 375, | 
|  | 196 | +    Op.LOG3: 4 * 375, | 
|  | 197 | +    Op.LOG4: 5 * 375, | 
|  | 198 | +    Op.CREATE: 32000, | 
|  | 199 | +    Op.CALL: 100, | 
|  | 200 | +    Op.CALLCODE: 100, | 
|  | 201 | +    Op.DELEGATECALL: 100, | 
|  | 202 | +    Op.CREATE2: 32000, | 
|  | 203 | +    Op.STATICCALL: 100, | 
|  | 204 | +    Op.SELFDESTRUCT: 5000, | 
|  | 205 | +} | 
|  | 206 | + | 
|  | 207 | +# PUSHx, SWAPx, DUPx have uniform gas costs | 
|  | 208 | +for opcode in set(Op): | 
|  | 209 | +    if 0x60 <= opcode.int() <= 0x9F: | 
|  | 210 | +        opcode_to_gas[opcode] = 3 | 
|  | 211 | + | 
|  | 212 | +constant_gas_opcodes = ( | 
|  | 213 | +    set(Op) | 
|  | 214 | +    - | 
|  | 215 | +    # zero constant gas opcodes - untestable | 
|  | 216 | +    {Op.STOP, Op.RETURN, Op.REVERT, Op.INVALID} | 
|  | 217 | +    - | 
|  | 218 | +    # TODO: EOF opcodes. Remove once EOF is removed | 
|  | 219 | +    set(V1_EOF_ONLY_OPCODES) | 
|  | 220 | +    - | 
|  | 221 | +    # SSTORE - untestable due to 2300 gas stipend rule | 
|  | 222 | +    {Op.SSTORE} | 
|  | 223 | +) | 
|  | 224 | + | 
|  | 225 | + | 
|  | 226 | +# NOTE: Gas costs varying across forks not being supported yet would make this | 
|  | 227 | +# test very complex. | 
|  | 228 | +@pytest.mark.valid_at("Osaka") | 
|  | 229 | +@pytest.mark.parametrize("opcode", sorted(constant_gas_opcodes)) | 
|  | 230 | +def test_constant_gas( | 
|  | 231 | +    state_test: StateTestFiller, pre: Alloc, opcode: Op, fork: Fork, env: Environment | 
|  | 232 | +) -> None: | 
|  | 233 | +    """Test that constant gas opcodes work as expected.""" | 
|  | 234 | +    warm_gas = opcode_to_gas[opcode] | 
|  | 235 | +    cold_gas = warm_gas + ( | 
|  | 236 | +        2500 | 
|  | 237 | +        if opcode | 
|  | 238 | +        in [ | 
|  | 239 | +            Op.BALANCE, | 
|  | 240 | +            Op.EXTCODESIZE, | 
|  | 241 | +            Op.EXTCODECOPY, | 
|  | 242 | +            Op.EXTCODEHASH, | 
|  | 243 | +            Op.CALL, | 
|  | 244 | +            Op.CALLCODE, | 
|  | 245 | +            Op.DELEGATECALL, | 
|  | 246 | +            Op.STATICCALL, | 
|  | 247 | +        ] | 
|  | 248 | +        else 2600 | 
|  | 249 | +        if opcode == Op.SELFDESTRUCT | 
|  | 250 | +        else 2000 | 
|  | 251 | +        if opcode == Op.SLOAD | 
|  | 252 | +        else 0 | 
|  | 253 | +    ) | 
|  | 254 | + | 
|  | 255 | +    if fork.transaction_gas_limit_cap(): | 
|  | 256 | +        env.gas_limit = fork.transaction_gas_limit_cap() | 
|  | 257 | + | 
|  | 258 | +    # Using `TLOAD` / `TSTORE` to work around warm/cold gas differences. We | 
|  | 259 | +    # need a counter to pick a distinct salt on each `CREATE2` and avoid | 
|  | 260 | +    # running into address conflicts. | 
|  | 261 | +    code_increment_counter = Op.TLOAD(1234) + Op.DUP1 + Op.TSTORE(1234, Op.PUSH1(1) + Op.ADD) | 
|  | 262 | +    setup_code = ( | 
|  | 263 | +        Op.MLOAD(0) | 
|  | 264 | +        + Op.POP | 
|  | 265 | +        + prepare_stack(opcode) | 
|  | 266 | +        + (code_increment_counter if opcode == Op.CREATE2 else Bytecode()) | 
|  | 267 | +    ) | 
|  | 268 | +    gas_test( | 
|  | 269 | +        state_test, | 
|  | 270 | +        env, | 
|  | 271 | +        pre, | 
|  | 272 | +        setup_code=setup_code, | 
|  | 273 | +        subject_code=opcode, | 
|  | 274 | +        tear_down_code=prepare_suffix(opcode), | 
|  | 275 | +        cold_gas=cold_gas, | 
|  | 276 | +        warm_gas=warm_gas, | 
|  | 277 | +        eof=False, | 
|  | 278 | +    ) | 
0 commit comments