|
22 | 22 | from pyk.konvert import kast_to_kore, kore_to_kast |
23 | 23 | from pyk.kore.parser import KoreParser |
24 | 24 | from pyk.kore.prelude import str_dv |
| 25 | +from pyk.kore.syntax import App, Pattern |
25 | 26 | from pyk.ktool.krun import KRunOutput, _krun |
26 | 27 | from pykwasm.wasm2kast import wasm2kast |
27 | 28 | from stellar_sdk import Network, StrKey, xdr |
@@ -67,19 +68,18 @@ def __init__(self, network_passphrase: str = Network.TESTNET_NETWORK_PASSPHRASE, |
67 | 68 | self.trace = trace |
68 | 69 |
|
69 | 70 | def _trace_config_vars(self) -> tuple[dict[str, str], dict[str, str]]: |
70 | | - return {'TRACE': str_dv(_TRACE_FILE).text}, {'TRACE': 'cat'} |
| 71 | + trace_path = _TRACE_FILE if self.trace else '' |
| 72 | + return {'TRACE': str_dv(trace_path).text}, {'TRACE': 'cat'} |
71 | 73 |
|
72 | 74 | def empty_config(self) -> str: |
73 | 75 | """Return the initial idle K configuration, with tracing enabled if requested.""" |
74 | | - kwargs: dict = {'output': KRunOutput.KORE} |
75 | | - if self.trace: |
76 | | - cmap, pmap = self._trace_config_vars() |
77 | | - kwargs['cmap'] = cmap |
78 | | - kwargs['pmap'] = pmap |
| 76 | + cmap, pmap = self._trace_config_vars() |
79 | 77 | res = self.definition.krun_with_kast( |
80 | 78 | pgm=steps_of([set_exit_code(0)]), |
81 | 79 | sort=KSort('Steps'), |
82 | | - **kwargs, |
| 80 | + output=KRunOutput.KORE, |
| 81 | + cmap=cmap, |
| 82 | + pmap=pmap, |
83 | 83 | ) |
84 | 84 | res.check_returncode() |
85 | 85 | return res.stdout |
@@ -357,6 +357,46 @@ def run_request_file(self, input_file: Path, request_str: str) -> InterpreterRes |
357 | 357 |
|
358 | 358 | return InterpreterResponse(final_kore=res.stdout, trace=trace) |
359 | 359 |
|
| 360 | + def run_transaction_with_trace( |
| 361 | + self, input_file: Path, transaction: Transaction, ledger_seq: int = 0 |
| 362 | + ) -> InterpreterResponse: |
| 363 | + """Like run_transaction but always produces a trace, regardless of self.trace.""" |
| 364 | + if self.trace: |
| 365 | + return self.run_transaction(input_file, transaction, ledger_seq) |
| 366 | + |
| 367 | + request_str = self.encode_transaction_to_json(transaction, ledger_seq) |
| 368 | + if request_str is not None: |
| 369 | + return self._run_request_file_force_trace(input_file, request_str) |
| 370 | + |
| 371 | + # KORE round-trip (wasm upload) — tracing not supported for this path |
| 372 | + return self.run_transaction(input_file, transaction, ledger_seq) |
| 373 | + |
| 374 | + def _run_request_file_force_trace(self, input_file: Path, request_str: str) -> InterpreterResponse: |
| 375 | + """Run request.json with tracing forced on by patching <ioDir> in state.kore.""" |
| 376 | + state_kore = KoreParser(input_file.read_text()).pattern() |
| 377 | + patched_kore = _set_io_dir(state_kore, _TRACE_FILE) |
| 378 | + |
| 379 | + with temp_working_directory() as root: |
| 380 | + (root / REQUEST_FILE).write_text(request_str) |
| 381 | + patched_state = root / 'state_traced.kore' |
| 382 | + patched_state.write_text(patched_kore.text) |
| 383 | + |
| 384 | + res = _krun( |
| 385 | + input_file=patched_state, |
| 386 | + definition_dir=self.definition.path, |
| 387 | + parser='cat', |
| 388 | + term=True, |
| 389 | + output=KRunOutput.KORE, |
| 390 | + check=False, |
| 391 | + ) |
| 392 | + |
| 393 | + if res.returncode: |
| 394 | + raise NodeInterpreterError(f'krun failed for traced request: {request_str}', res) |
| 395 | + |
| 396 | + trace_file = root / _TRACE_FILE |
| 397 | + trace = trace_file.read_text() if trace_file.exists() else None |
| 398 | + return InterpreterResponse(final_kore=res.stdout, trace=trace) |
| 399 | + |
360 | 400 | def run_steps(self, input_file: Path, steps: Iterable[KInner]) -> InterpreterResponse: |
361 | 401 | input_state_kore = KoreParser(input_file.read_text()).pattern() |
362 | 402 | input_state_kast = kore_to_kast(self.definition.kdefinition, input_state_kore) |
@@ -432,5 +472,14 @@ def _encode_scval(scval: xdr.SCVal) -> dict: |
432 | 472 | raise NotImplementedError(f'Unsupported SCVal type for JSON encoding: {scval.type}') |
433 | 473 |
|
434 | 474 |
|
| 475 | +def _set_io_dir(pattern: Pattern, path: str) -> Pattern: |
| 476 | + """Walk a KORE pattern and set the <ioDir> cell value to `path`.""" |
| 477 | + if isinstance(pattern, App): |
| 478 | + if pattern.symbol == "Lbl'-LT-'ioDir'-GT-'": |
| 479 | + return App(pattern.symbol, pattern.sorts, (str_dv(path),)) |
| 480 | + return App(pattern.symbol, pattern.sorts, tuple(_set_io_dir(a, path) for a in pattern.args)) |
| 481 | + return pattern |
| 482 | + |
| 483 | + |
435 | 484 | class NodeInterpreterError(RuntimeError): |
436 | 485 | pass |
0 commit comments