|
15 | 15 | from pyk.kcfg import KCFG, KCFGExplore
|
16 | 16 | from pyk.kdist import kdist
|
17 | 17 | from pyk.kore.rpc import KoreClient
|
18 |
| -from pyk.prelude.kint import euclidModInt |
19 |
| -from pyk.prelude.ml import mlEquals, mlEqualsFalse, mlNot |
| 18 | +from pyk.prelude.kint import addInt, euclidModInt, leInt |
| 19 | +from pyk.prelude.ml import mlEquals, mlEqualsFalse, mlEqualsTrue, mlNot |
20 | 20 | from pyk.proof import APRProof
|
21 | 21 | from pyk.proof.show import APRProofShow
|
22 | 22 | from pyk.utils import ensure_dir_path
|
@@ -286,30 +286,28 @@ def get_todo_list() -> list[str]:
|
286 | 286 | return todo_list
|
287 | 287 |
|
288 | 288 |
|
289 |
| -def stack_needed(opcode_id: str) -> list[int]: |
| 289 | +def stack_needed(opcode_id: str) -> int: |
290 | 290 | """
|
291 | 291 | Return the stack size needed for the opcode, corresponding `#stackNeeded` in the semantics.
|
292 | 292 | """
|
293 | 293 | opcode = OPCODES[opcode_id].label.name
|
294 | 294 | if 'CallOp' in opcode:
|
295 |
| - return [7] |
| 295 | + return 7 |
296 | 296 | elif 'CallSixOp' in opcode:
|
297 |
| - return [6] |
| 297 | + return 6 |
298 | 298 | elif 'LOG' in opcode:
|
299 |
| - return list(range(5)) |
| 299 | + return 2 |
300 | 300 | elif 'SWAP' in opcode:
|
301 |
| - return list(range(1, 17)) |
302 |
| - elif 'DUP' in opcode: |
303 |
| - return list(range(1, 17)) |
| 301 | + return 1 |
304 | 302 | elif 'QuadStackOp' in opcode:
|
305 |
| - return [4] |
| 303 | + return 4 |
306 | 304 | elif 'TernStackOp' in opcode:
|
307 |
| - return [3] |
| 305 | + return 3 |
308 | 306 | elif 'BinStackOp' in opcode:
|
309 |
| - return [2] |
| 307 | + return 2 |
310 | 308 | elif 'UnStackOp' in opcode:
|
311 |
| - return [1] |
312 |
| - return [0] |
| 309 | + return 1 |
| 310 | + return 0 |
313 | 311 |
|
314 | 312 |
|
315 | 313 | def accounts_cell(acct_id: str | KInner, exists: bool = True) -> tuple[KInner, KInner]:
|
@@ -451,59 +449,72 @@ def _build_spec(
|
451 | 449 | return APRProof.from_claim(self.kevm.definition, kclaim[0], {}, self.proof_dir)
|
452 | 450 |
|
453 | 451 | def build_spec(self, opcode_symbol: str) -> list[APRProof]:
|
454 |
| - needs = stack_needed(opcode_symbol) |
| 452 | + |
| 453 | + def _ws_size(s: int) -> KInner: |
| 454 | + return KEVM.size_wordstack(KEVM.wordstack(s)) |
| 455 | + |
| 456 | + def _le(a: KInner, b: KInner) -> KInner: |
| 457 | + return mlEqualsTrue(leInt(a, b)) |
| 458 | + |
| 459 | + need = stack_needed(opcode_symbol) |
455 | 460 | opcode = OPCODES[opcode_symbol]
|
456 |
| - proofs = [] |
457 |
| - for need in needs: |
458 |
| - if len(needs) > 1: |
459 |
| - opcode = KApply(opcode.label.name, KToken(str(need), KSort('Int'))) |
460 |
| - |
461 |
| - # (opcode, init_subst, init_constraints, final_subst, final_constraints, id_str) |
462 |
| - specs: list[tuple[KApply, dict[str, KInner], list[KInner], dict[str, KInner], list[KInner], str]] = [] |
463 |
| - init_subst: dict[str, KInner] = {} |
464 |
| - final_subst: dict[str, KInner] = {} |
465 |
| - |
466 |
| - if opcode_symbol in NOT_USEGAS_OPCODES: |
467 |
| - # TODO: Should allow infGas to calculate gas. Skip for now. |
468 |
| - init_subst['USEGAS_CELL'] = KToken('false', KSort('Bool')) |
469 |
| - |
470 |
| - if opcode_symbol in ACCOUNT_QUERIES_OPCODES: |
471 |
| - w0 = KVariable('W0', KSort('Int')) |
472 |
| - pow160 = KToken(str(pow(2, 160)), KSort('Int')) |
473 |
| - |
474 |
| - cell, constraint = accounts_cell(euclidModInt(w0, pow160), exists=False) |
475 |
| - init_subst['ACCOUNTS_CELL'] = cell |
476 |
| - # TODO: BALANCE doesn't need the above spec. Maybe a bug in the backend. |
477 |
| - specs.append((opcode, init_subst, [constraint], {}, [], '_OWISE')) |
478 |
| - |
479 |
| - cell, constraint = accounts_cell(euclidModInt(w0, pow160), exists=True) |
480 |
| - init_subst['ACCOUNTS_CELL'] = cell |
481 |
| - specs.append((opcode, init_subst, [constraint], {}, [], '_NORMAL')) |
482 |
| - elif opcode_symbol in ACCOUNT_STORAGE_OPCODES or opcode_symbol == 'SELFBALANCE': |
483 |
| - cell, constraint = accounts_cell('ID_CELL') |
484 |
| - init_subst['ACCOUNTS_CELL'] = cell |
485 |
| - specs.append((opcode, init_subst, [constraint], {}, [], '')) |
486 |
| - elif opcode_symbol == 'JUMP': |
487 |
| - final_subst['K_CELL'] = KSequence([KEVM.end_basic_block(), KVariable('K_CELL')]) |
488 |
| - specs.append((opcode, init_subst, [], final_subst, [], '')) |
489 |
| - elif opcode_symbol == 'JUMPI': |
490 |
| - constraint = mlEquals(KVariable('W1', KSort('Int')), KToken('0', KSort('Int')), 'Int') |
491 |
| - specs.append((opcode, init_subst, [constraint], {}, [], '_FALSE')) |
492 |
| - |
493 |
| - constraint = mlNot(mlEquals(KVariable('W1', KSort('Int')), KToken('0', KSort('Int')), 'Int')) |
494 |
| - final_subst['K_CELL'] = KSequence([KEVM.end_basic_block(), KVariable('K_CELL')]) |
495 |
| - specs.append((opcode, init_subst, [], final_subst, [], '_TRUE')) |
496 |
| - elif opcode_symbol == 'LOG': |
497 |
| - need += 2 |
498 |
| - specs.append((opcode, init_subst, [], final_subst, [], '')) |
499 |
| - else: |
500 |
| - specs.append((opcode, init_subst, [], final_subst, [], '')) |
501 |
| - |
502 |
| - for spec in specs: |
503 |
| - proof = self._build_spec(spec[0], need, spec[1], spec[2], spec[3], spec[4], id_str=spec[5]) |
504 |
| - proofs.append(proof) |
505 |
| - |
506 |
| - return proofs |
| 461 | + |
| 462 | + if opcode_symbol in ['DUP', 'SWAP', 'LOG']: |
| 463 | + opcode = KApply(opcode.label.name, KVariable('N', KSort('Int'))) |
| 464 | + |
| 465 | + # (opcode, init_subst, init_constraints, final_subst, final_constraints, id_str) |
| 466 | + specs: list[tuple[KApply, dict[str, KInner], list[KInner], dict[str, KInner], list[KInner], str]] = [] |
| 467 | + init_subst: dict[str, KInner] = {} |
| 468 | + final_subst: dict[str, KInner] = {} |
| 469 | + |
| 470 | + if opcode_symbol in NOT_USEGAS_OPCODES: |
| 471 | + # TODO: Should allow infGas to calculate gas. Skip for now. |
| 472 | + init_subst['USEGAS_CELL'] = KToken('false', KSort('Bool')) |
| 473 | + |
| 474 | + if opcode_symbol in ACCOUNT_QUERIES_OPCODES: |
| 475 | + w0 = KVariable('W0', KSort('Int')) |
| 476 | + pow160 = KToken(str(pow(2, 160)), KSort('Int')) |
| 477 | + |
| 478 | + cell, constraint = accounts_cell(euclidModInt(w0, pow160), exists=False) |
| 479 | + init_subst['ACCOUNTS_CELL'] = cell |
| 480 | + # TODO: BALANCE doesn't need the above spec. Maybe a bug in the backend. |
| 481 | + specs.append((opcode, init_subst, [constraint], {}, [], '_OWISE')) |
| 482 | + |
| 483 | + cell, constraint = accounts_cell(euclidModInt(w0, pow160), exists=True) |
| 484 | + init_subst['ACCOUNTS_CELL'] = cell |
| 485 | + specs.append((opcode, init_subst, [constraint], {}, [], '_NORMAL')) |
| 486 | + elif opcode_symbol in ACCOUNT_STORAGE_OPCODES or opcode_symbol == 'SELFBALANCE': |
| 487 | + cell, constraint = accounts_cell('ID_CELL') |
| 488 | + init_subst['ACCOUNTS_CELL'] = cell |
| 489 | + specs.append((opcode, init_subst, [constraint], {}, [], '')) |
| 490 | + elif opcode_symbol == 'JUMP': |
| 491 | + final_subst['K_CELL'] = KSequence([KEVM.end_basic_block(), KVariable('K_CELL')]) |
| 492 | + specs.append((opcode, init_subst, [], final_subst, [], '')) |
| 493 | + elif opcode_symbol == 'JUMPI': |
| 494 | + constraint = mlEquals(KVariable('W1', KSort('Int')), KToken('0', KSort('Int')), 'Int') |
| 495 | + specs.append((opcode, init_subst, [constraint], {}, [], '_FALSE')) |
| 496 | + |
| 497 | + constraint = mlNot(mlEquals(KVariable('W1', KSort('Int')), KToken('0', KSort('Int')), 'Int')) |
| 498 | + final_subst['K_CELL'] = KSequence([KEVM.end_basic_block(), KVariable('K_CELL')]) |
| 499 | + specs.append((opcode, init_subst, [], final_subst, [], '_TRUE')) |
| 500 | + elif opcode_symbol == 'DUP': |
| 501 | + init_constraints: list[KInner] = [_le(KVariable('N', 'Int'), _ws_size(0))] |
| 502 | + init_constraints.append(_le(_ws_size(0), KToken('1023', 'Int'))) |
| 503 | + specs.append((opcode, init_subst, init_constraints, final_subst, [], '')) |
| 504 | + elif opcode_symbol == 'SWAP': |
| 505 | + init_constraints = [_le(addInt(KVariable('N', 'Int'), KToken('1', 'Int')), _ws_size(1))] |
| 506 | + init_constraints.append(_le(_ws_size(1), KToken('1023', 'Int'))) |
| 507 | + specs.append((opcode, init_subst, init_constraints, final_subst, [], '')) |
| 508 | + elif opcode_symbol == 'LOG': |
| 509 | + init_constraints = [_le(addInt(KVariable('N', 'Int'), KToken('2', 'Int')), _ws_size(2))] |
| 510 | + init_constraints.append(_le(KVariable('N', 'Int'), _ws_size(0))) |
| 511 | + init_constraints.append(_le(_ws_size(2), addInt(KVariable('N', 'Int'), KToken('1026', 'Int')))) |
| 512 | + init_subst['STATIC_CELL'] = KToken('false', KSort('Bool')) |
| 513 | + specs.append((opcode, init_subst, init_constraints, final_subst, [], '')) |
| 514 | + else: |
| 515 | + specs.append((opcode, init_subst, [], final_subst, [], '')) |
| 516 | + |
| 517 | + return [self._build_spec(spec[0], need, spec[1], spec[2], spec[3], spec[4], spec[5]) for spec in specs] |
507 | 518 |
|
508 | 519 | def explore(self, proof: APRProof) -> bool:
|
509 | 520 | """
|
|
0 commit comments