Skip to content

Conversation

@tomusdrw
Copy link
Contributor

  • Handle host calls.
  • Initial version of host calls handling.

@netlify
Copy link

netlify bot commented Nov 29, 2025

Deploy Preview for pvm-debugger ready!

Name Link
🔨 Latest commit 37ebdf7
🔍 Latest deploy log https://app.netlify.com/projects/pvm-debugger/deploys/692ef8baace89b0009ac2b9f
😎 Deploy Preview https://deploy-preview-455--pvm-debugger.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 29, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive host call debugging system to the PVM debugger. It adds a HostCallDialog component with specialized handlers for different host call types (Gas, Fetch, Info, Log, Provide, Read, Transfer, Write, Yield), supporting utilities for memory simulation and state management, and new web worker command handlers. The @typeberry/lib dependency is also updated.

Changes

Cohort / File(s) Summary
Dependencies
package.json
Updated @typeberry/lib from ^0.4.1-ea3c83c to ^0.4.1-3923458
Host Call Dialog—Core
src/App.tsx, src/components/HostCallDialog/index.tsx, src/components/HostCallDialog/DefaultHostCallContent.tsx, src/components/HostCallDialog/MemoryEditor.tsx
New HostCallDialog component and supporting base UI components for rendering host call state, memory editor, and generic host call content display
Host Call Handlers
src/components/HostCallDialog/handlers/GasHostCall.tsx, src/components/HostCallDialog/handlers/FetchHostCall.tsx, src/components/HostCallDialog/handlers/InfoHostCall.tsx, src/components/HostCallDialog/handlers/LogHostCall.tsx, src/components/HostCallDialog/handlers/ProvideHostCall.tsx, src/components/HostCallDialog/handlers/ReadHostCall.tsx, src/components/HostCallDialog/handlers/TransferHostCall.tsx, src/components/HostCallDialog/handlers/WriteHostCall.tsx, src/components/HostCallDialog/handlers/YieldHostCall.tsx
Nine specialized host call handlers simulating and rendering UI for each host call type
Host Call Handler Infrastructure
src/components/HostCallDialog/handlers/types.ts, src/components/HostCallDialog/handlers/index.ts, src/components/HostCallDialog/handlers/HostCallActionButtons.tsx, src/components/HostCallDialog/handlers/hostCallUtils.ts, src/components/HostCallDialog/handlers/storageManager.ts
Types, registry, utilities (MockMemory, MockGasCounter, hex/bytes conversion), storage manager, and action buttons for host call handlers
Web Worker Commands
src/packages/web-worker/command-handlers/set-state.ts, src/packages/web-worker/command-handlers/set-memory.ts, src/packages/web-worker/command-handlers/index.ts, src/packages/web-worker/command-handlers/memory.ts, src/packages/web-worker/types.ts, src/packages/web-worker/worker.ts
New SET_STATE and SET_MEMORY command handlers for web worker; added error context to memory command diagnostics
Redux Store Updates
src/store/workers/workersSlice.ts, src/store/debugger/debuggerSlice.ts
New thunks (readMemoryRange, resumeAfterHostCall), host call state management, and revised handleHostCall fallback to open dialog instead of error
Type Definitions & Constants
src/types/pvm.ts
New exported constants DEFAULT_REGS and DEFAULT_GAS
Existing Component Integration
src/components/DebuggerSettings/Content.tsx, src/components/ProgramLoader/Examples.tsx, src/components/ProgramLoader/Loader.tsx, src/components/ProgramLoader/examplePrograms.ts, src/components/ProgramLoader/loadingUtils.ts, src/components/Instructions/BasicBlocks/CollapsibleInstructionsTable.tsx, src/components/Registers/index.tsx, src/pages/ProgramLoader.tsx, src/hooks/useDebuggerActions.ts
Updated to integrate host call system: blob-based SPI args handling, storage manager initialization, default gas usage, error handling in args decoder, and register status display enhancement

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Each host call handler requires independent logic review; handlers differ significantly in their execution patterns (Gas uses mocked Gas, Fetch constructs fake memory, Info parses form inputs, etc.)
  • HostCallContext and utilities (MockMemory, MockGasCounter, hex/bytes conversions) need careful validation for correctness
  • Redux thunk implementations (readMemoryRange, resumeAfterHostCall) coordinate multiple operations and state transitions
  • MemoryEditor component with per-byte editing and hex input validation
  • Web worker command handlers and type integration with existing worker infrastructure
  • Integration points across multiple existing components (DebuggerSettings, ProgramLoader, Registers, etc.) need verification for consistency

Possibly related PRs

  • PR #451: Both PRs modify SPI loading, ProgramLoader, default constants (DEFAULT_GAS, DEFAULT_REGS), web worker initialization, and @typeberry/lib versioning, indicating a closely related feature implementation.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'host calls wip' is vague and uses non-standard abbreviations ('wip' likely meaning 'work in progress'), making it unclear without context. Replace with a more descriptive title like 'Add host call dialog and handlers' or 'Implement host call UI and execution framework'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description mentions 'Handle host calls' and 'Initial version of host calls handling', which aligns with the extensive host call infrastructure added throughout the changeset.

Comment @coderabbitai help to get the list of available commands and usage tips.

@tomusdrw tomusdrw marked this pull request as ready for review December 2, 2025 14:16
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/ProgramLoader/examplePrograms.ts (2)

54-54: Inconsistent gas value: Use DEFAULT_GAS or document the reason.

The gameOfLife program uses a hardcoded gas value of 10_000_000n, while other programs (fibonacci, add, storeU16, empty) now use DEFAULT_GAS. This inconsistency undermines the centralization effort. If this program requires more gas, consider documenting why with a comment.

Apply this diff to use the default:

-    gas: 10_000_000n,
+    gas: DEFAULT_GAS,

Or document the special requirement:

-    gas: 10_000_000n,
+    // Game of Life requires more gas due to complex simulation
+    gas: 10_000_000n,

63-63: Inconsistent gas value: Use DEFAULT_GAS or document the reason.

The branch program uses a hardcoded gas value of 10n, while other programs now use DEFAULT_GAS. This inconsistency undermines the centralization effort. If this minimal gas is intentional for testing purposes, consider documenting it.

Apply this diff to use the default:

-    gas: 10n,
+    gas: DEFAULT_GAS,

Or document the special requirement:

-    gas: 10n,
+    // Minimal gas for testing branch behavior
+    gas: 10n,
🧹 Nitpick comments (32)
src/components/Registers/index.tsx (1)

14-14: Host status formatter: enum key casing and multi‑worker exitArg handling

The new formatter logic looks good for enriching the status label, but there are two potential pitfalls worth checking:

  • Enum key casing: statusValue === Status.HOST assumes a HOST member. If your Status type/enum uses names like Host (as suggested by the worker Status mapping), this will either not compile or always be false, and displayText/extra classes will never be applied for host status. Please confirm the actual Status definition and align the member name accordingly.

  • Using only workers[0]?.exitArg: You’re always reading exitArg from the first worker, both for the main cell and the per‑worker tooltip rows (since formatter closes over workers and formatValueToDisplay applies it to each worker’s value). If multiple workers can have different exitArg values, this will misrepresent them in the tooltip and in the summary. Consider deriving exitArg from the worker whose value you’re formatting (or from a selected/active worker in state) instead of hard‑coding index 0.

Also applies to: 175-193

src/packages/web-worker/command-handlers/set-memory.ts (1)

1-35: SetMemory handler shape looks good; consider awaiting setMemory

The handler’s null-check and structured CommandStatus responses look consistent with other worker commands. Given runSetMemory is async, it would be safer to await the PVM call so any async failures are caught by this try/catch:

-  try {
-    // Use the PVM's setMemory API to write data
-    pvm.setMemory(address, data);
+  try {
+    // Use the PVM's setMemory API to write data
+    await pvm.setMemory(address, data);

This is a no-op if setMemory is currently synchronous but future‑proofs the handler if the API becomes async. As per coding guidelines, this keeps the worker RPC behavior predictable for WASM-facing consumers.

src/components/ProgramLoader/Examples.tsx (1)

9-9: SPI args integration into Doom/GoL example loads looks correct

Reading spiArgs from state.debugger.spiArgs and threading it into loadFileFromUint8Array for the Doom and GoL examples brings these flows in line with the rest of the SPI-loading pipeline, and should work well with the spiArgsAsBytes handling inside the loader.

As a minor hardening step, you might eventually want to pass a well-typed initialState object instead of {} in these two calls so that, if the detection logic ever falls back to the generic PVM path, it doesn’t rely on an empty object.

Also applies to: 14-14, 59-60, 79-80

src/components/Instructions/BasicBlocks/CollapsibleInstructionsTable.tsx (1)

23-23: Defensive ArgsDecoder initialization avoids crashes in widestItemValue

Wrapping decodeAndGetArgsDecoder(program) in a try/catch here and falling back to "" if decoding fails is a sensible way to prevent broken/partial programs from crashing the instructions table while computing column widths. If you find it useful during debugging, you could also log the decode failure once inside the catch, but the current behavior is acceptable and keeps the UI resilient.

Also applies to: 169-174

src/components/HostCallDialog/handlers/storageManager.ts (2)

26-38: Write method behavior is clear but consider edge cases.

The write() method's delete-on-null behavior is well-documented. However, consider:

  1. The return value (previous length) might be unexpected for callers expecting a boolean or void
  2. No validation that value is a valid Uint8Array when non-null

Consider adding a validation check:

  write(key: BytesBlob, value: Uint8Array | null): number | null {
    const keyHex = key.toString();
    const previousValue = this.storage.get(keyHex);
    const previousLength = previousValue ? previousValue.length : null;

    if (value === null) {
      this.storage.delete(keyHex);
    } else {
+     if (!(value instanceof Uint8Array)) {
+       throw new TypeError('Value must be a Uint8Array');
+     }
      this.storage.set(keyHex, new Uint8Array(value));
    }

    return previousLength;
  }

9-61: Consider adding a method to get storage size.

For debugging and monitoring purposes, consider adding a method to get the current storage size (number of entries or total bytes).

/**
 * Get the number of entries in storage.
 */
getSize(): number {
  return this.storage.size;
}

/**
 * Get the total number of bytes stored.
 */
getTotalBytes(): number {
  let total = 0;
  for (const value of this.storage.values()) {
    total += value.length;
  }
  return total;
}
src/packages/web-worker/command-handlers/set-state.ts (1)

17-67: Consider using DEFAULT_REGS for initialization.

The PR introduces DEFAULT_REGS constant in src/types/pvm.ts. Consider whether this handler should support resetting to default values when regs is not provided or is empty.

Example enhancement:

import { DEFAULT_REGS } from "@/types/pvm";

export type SetStateParams = {
  pvm: PvmApiInterface | null;
  regs?: bigint[]; // Make optional
  gas: bigint;
};

// Inside runSetState:
const regsToSet = regs && regs.length === 13 ? regs : DEFAULT_REGS;
src/components/HostCallDialog/handlers/ProvideHostCall.tsx (2)

44-66: Consider extracting common partialState stubs to reduce duplication.

The partialState object is duplicated in both the mount effect and handleResume. The stub methods (transfer, checkPreimageStatus, etc.) are identical. Consider extracting a factory function or base object:

+// At module level or inside component
+const createBasePartialState = (resolvedServiceId: ReturnType<typeof block.tryAsServiceId>): Omit<PartialState, 'providePreimage'> => ({
+  transfer: () => Result.ok(OK),
+  checkPreimageStatus: () => null,
+  requestPreimage: () => Result.ok(OK),
+  forgetPreimage: () => Result.ok(OK),
+  eject: () => Result.ok(OK),
+  newService: () => Result.ok(resolvedServiceId),
+  upgradeService: () => {},
+  updateValidatorsData: () => Result.ok(OK),
+  checkpoint: () => {},
+  updateAuthorizationQueue: () => Result.ok(OK),
+  updatePrivilegedServices: () => Result.ok(OK),
+  yield: () => {},
+});

// Then use:
 const partialState: PartialState = {
+  ...createBasePartialState(resolvedServiceId),
   providePreimage: (service, preimage) => { /* capture logic */ },
-  transfer: () => Result.ok(OK),
-  // ... rest of stubs
 };

Also applies to: 99-113


94-135: Consider extracting memory preloading logic.

The memory preloading pattern (lines 117-122) duplicates lines 72-77. This could be extracted to a helper function for maintainability.

Additionally, the async handleResume sets isExecuting to true but doesn't have cleanup if the component unmounts during execution. This is a minor concern since onResume likely navigates away.

+const preloadPreimageMemory = async (
+  ctx: HostCallContext,
+  regs: bigint[],
+  readMemory: (addr: number, len: number) => Promise<Uint8Array>
+) => {
+  const preimagePointer = Number(regs[8] ?? 0n);
+  const preimageLength = Number(regs[9] ?? 0n);
+  if (preimagePointer > 0 && preimageLength > 0) {
+    const preimageData = await readMemory(preimagePointer, preimageLength);
+    ctx.preloadMemory(preimagePointer, preimageData);
+  }
+};
src/components/HostCallDialog/MemoryEditor.tsx (3)

51-77: onMemoryChange in dependency array may cause spurious reloads.

The onMemoryChange callback is included in the dependency array but isn't used inside the effect. If the parent doesn't memoize this callback, the effect will re-run on every parent render, triggering unnecessary memory fetches.

   useEffect(() => {
     const loadMemory = async () => {
       // ...loading logic
     };
 
     loadMemory();
-  }, [address, length, readMemory, onMemoryChange]);
+  }, [address, length, readMemory]);

115-129: Single-byte edit sends entire buffer; address is view start, not edited byte.

When editing one byte, onMemoryChange receives the view's start address and the entire buffer. If consumers expect per-byte edits (as MemoryEdit suggests), this could cause issues or inefficiencies. Consider sending only the edited byte's address and value.

   const handleByteBlur = useCallback(() => {
     if (editingByte === null || !data || address === null) {
       setEditingByte(null);
       return;
     }
 
     const byteValue = parseInt(editValue || "0", 16);
     if (!isNaN(byteValue) && byteValue >= 0 && byteValue <= 255) {
       const newData = new Uint8Array(data);
       newData[editingByte] = byteValue;
       setData(newData);
-      onMemoryChange?.(address, newData);
+      // Send only the edited byte's address and value
+      onMemoryChange?.(address + editingByte, new Uint8Array([byteValue]));
     }
     setEditingByte(null);
   }, [editingByte, editValue, data, address, onMemoryChange]);

158-176: Labels not associated with inputs via htmlFor/id.

The <label> elements are not programmatically linked to their corresponding inputs, which reduces accessibility for screen readers.

         <div className="flex-1">
-          <label className="text-sm font-medium">Start Address</label>
+          <label htmlFor="memory-start-address" className="text-sm font-medium">Start Address</label>
           <Input
+            id="memory-start-address"
             className="font-mono"
             placeholder="0x1000"
             value={addressInput}
             onChange={(e) => updateAddress(e.target.value)}
             disabled={disabled}
           />
         </div>
         <div className="flex-1">
-          <label className="text-sm font-medium">Length (max {MAX_LENGTH})</label>
+          <label htmlFor="memory-length" className="text-sm font-medium">Length (max {MAX_LENGTH})</label>
           <Input
+            id="memory-length"
             className="font-mono"
             placeholder="256"
             value={lengthInput}
             onChange={(e) => updateLength(e.target.value)}
             disabled={disabled}
           />
         </div>
src/components/HostCallDialog/handlers/FetchHostCall.tsx (1)

91-95: Effect resets input to same constant on every fetchKind change.

The effect resets hexInput to DEFAULT_CONSTANTS whenever fetchKind changes. Since DEFAULT_CONSTANTS is a constants-specific value, this may not be appropriate for other fetch kinds (Entropy, WorkPackage, etc.). Consider using kind-specific defaults or preserving user input.

src/components/HostCallDialog/handlers/InfoHostCall.tsx (3)

48-52: Effect with empty dependency array doesn't reset on dialog reopen.

The effect runs only once on mount. If the component isn't unmounted between dialog opens (e.g., kept in DOM but hidden), the form won't reset. Consider adding hasHostCallOpen or similar dependency, or resetting in a parent-controlled manner.


58-76: No input validation before BigInt/Number parsing.

BigInt(balance) and similar calls will throw SyntaxError if the string is empty or invalid (e.g., "abc"). While the outer try-catch handles this, the error message will be cryptic. Consider validating inputs before parsing or providing field-specific error feedback.

     try {
       // Parse form values
       const codeHashBytes = bytes.BytesBlob.parseBlob(codeHash).raw;
       if (codeHashBytes.length !== 32) {
         throw new Error("Code hash must be exactly 32 bytes");
       }
 
+      // Validate numeric inputs
+      const numericFields = { balance, accumulateMinGas, onTransferMinGas, storageBytes, gratisStorage };
+      for (const [name, value] of Object.entries(numericFields)) {
+        if (!/^\d+$/.test(value.trim())) {
+          throw new Error(`${name} must be a valid non-negative integer`);
+        }
+      }
+
       const serviceInfo = ServiceAccountInfo.create({

90-95: isExecuting not reset on success path.

When onResume succeeds, isExecuting remains true. If the dialog doesn't unmount (e.g., due to an error in the resume flow after this component's try block), the buttons stay disabled permanently.

       const { modifiedRegs, finalGas, memoryEdits } = ctx.getResult();
 
       onResume(mode, modifiedRegs, finalGas, memoryEdits);
+      setIsExecuting(false);
     } catch (e) {
       console.error(e);
       setError(e instanceof Error ? e.message : "Failed to execute info");
       setIsExecuting(false);
     }
src/components/HostCallDialog/index.tsx (1)

112-125: Memory edit merge by address may cause data loss with overlapping ranges.

The merge logic replaces edits at the same start address. If one edit writes bytes at address 0x1000 (length 256) and another at 0x1000 (length 1), the first is replaced entirely. Consider merging by range overlap or using a more sophisticated merge strategy.

src/components/HostCallDialog/handlers/ReadHostCall.tsx (2)

38-92: Potential stale closure risk with onResume in effect dependencies.

The onResume callback is included in the dependency array but the effect is guarded by hasExecuted.current, meaning subsequent identity changes won't trigger re-execution. If onResume changes after the initial execution but before auto-resume completes, the stale callback could be invoked at line 79.

Consider extracting onResume from the dependency array and using a ref to hold the latest callback, or ensure the parent component memoizes onResume with useCallback.


62-69: Consider extracting memory preloading into a helper.

The key memory preloading logic (lines 62-69) is duplicated in handleResume (lines 121-127). For maintainability, consider extracting this into a small helper function within the component.

+  const preloadKeyMemory = useCallback(async (ctx: HostCallContext) => {
+    const keyPointer = Number(regs[8] ?? 0n);
+    const keyLength = Number(regs[9] ?? 0n);
+    if (keyLength > 0) {
+      const keyData = await readMemory(keyPointer, keyLength);
+      ctx.preloadMemory(keyPointer, keyData);
+    }
+  }, [regs, readMemory]);

Also applies to: 121-127

src/components/HostCallDialog/DefaultHostCallContent.tsx (2)

54-56: Consider extracting the gas adjustment constant.

The magic number 10n for gas adjustment should be a named constant to improve readability and maintainability.

+const HOST_CALL_GAS_COST = 10n;
+
 // Set gas to current gas - 10 (as per requirement)
 const currentGas = currentState.gas ?? DEFAULT_GAS;
-const newGas = currentGas > 10n ? currentGas - 10n : 0n;
+const newGas = currentGas > HOST_CALL_GAS_COST ? currentGas - HOST_CALL_GAS_COST : 0n;

62-70: Avoid calling callbacks inside setState updater functions.

Invoking onRegsChange inside the setRegs updater is a side effect within React's state update, which is unconventional and may cause issues with React's batching or concurrent features.

 const handleRegisterChange = (index: number, value: string) => {
   const newValue = stringToNumber(value, BigInt);
-  setRegs((prev) => {
-    const newRegs = [...prev];
-    newRegs[index] = newValue;
-    onRegsChange(newRegs);
-    return newRegs;
-  });
+  const newRegs = [...regs];
+  newRegs[index] = newValue;
+  setRegs(newRegs);
+  onRegsChange(newRegs);
 };
src/components/HostCallDialog/handlers/YieldHostCall.tsx (2)

43-62: Extract duplicate partialState stub into a factory or constant.

The partialState object is defined twice with nearly identical stub implementations. Consider extracting a factory function to reduce duplication and ensure consistency.

+const createPartialStateStub = (
+  resolvedServiceId: ReturnType<typeof block.tryAsServiceId>,
+  onYield?: (hash: OpaqueHash) => void
+): PartialState => ({
+  yield: onYield ?? (() => {}),
+  transfer: () => Result.ok(OK),
+  checkPreimageStatus: () => null,
+  requestPreimage: () => Result.ok(OK),
+  forgetPreimage: () => Result.ok(OK),
+  eject: () => Result.ok(OK),
+  newService: () => Result.ok(resolvedServiceId),
+  upgradeService: () => {},
+  updateValidatorsData: () => Result.ok(OK),
+  checkpoint: () => {},
+  updateAuthorizationQueue: () => Result.ok(OK),
+  updatePrivilegedServices: () => Result.ok(OK),
+  providePreimage: () => Result.ok(OK),
+});

Also applies to: 95-109


44-47: Consider using a shared utility for bytes-to-hex conversion.

The manual hex conversion could be extracted to a utility function in hostCallUtils.ts for consistency with other conversions like hexToAscii.

src/components/HostCallDialog/handlers/TransferHostCall.tsx (2)

45-68: Extract duplicate partialState stub to reduce code duplication.

Similar to other handlers, the partialState object is duplicated between the initial execution and handleResume. This pattern repeats across multiple host call handlers (YieldHostCall, TransferHostCall, etc.) and could benefit from a shared factory function.

Also applies to: 101-115


74-79: Extract MEMO_SIZE as a module-level constant.

The constant is defined inline and duplicated. Moving it to module scope improves clarity.

+const MEMO_SIZE = 128; // TRANSFER_MEMO_BYTES
+
 // Inside execute function:
-const MEMO_SIZE = 128; // TRANSFER_MEMO_BYTES
 if (memoPointer > 0) {
src/components/HostCallDialog/handlers/WriteHostCall.tsx (3)

83-148: Consider extracting duplicate memory preloading logic.

The memory preloading logic for key and value (lines 102-123) is duplicated in handleResume (lines 172-188). Consider extracting this into a shared helper function to reduce code duplication and maintenance burden.

+const preloadKeyValueMemory = async (
+  ctx: HostCallContext,
+  regs: bigint[],
+  readMemory: (address: number, length: number) => Promise<Uint8Array>
+) => {
+  const keyPointer = Number(regs[7] ?? 0n);
+  const keyLength = Number(regs[8] ?? 0n);
+  let keyHex = "";
+  if (keyLength > 0) {
+    const keyData = await readMemory(keyPointer, keyLength);
+    ctx.preloadMemory(keyPointer, keyData);
+    keyHex = bytesToHex(keyData);
+  }
+
+  const valuePointer = regs[9] ?? 0n;
+  const valueLength = Number(regs[10] ?? 0n);
+  const MAX_U64 = 0xffffffffffffffffn;
+  const isDelete = valuePointer >= MAX_U64;
+  let valueHex: string | null = null;
+  if (!isDelete && valueLength > 0) {
+    const valueData = await readMemory(Number(valuePointer), valueLength);
+    ctx.preloadMemory(Number(valuePointer), valueData);
+    valueHex = bytesToHex(valueData);
+  }
+
+  return { keyHex, keyLength, valueHex, valueLength, isDelete };
+};

196-200: Inconsistent error message handling between initial execution and resume.

The initial execution (line 142) extracts the message from the error object, but handleResume (line 198) uses a generic fallback. Consider applying the same detailed error extraction pattern for consistency.

     } catch (e) {
       console.error(e);
-      setError(e instanceof Error ? e.message : "Failed to execute write");
+      const msg = e !== null && typeof e === "object" && "message" in e ? (e as { message: string }).message : "";
+      setError(e instanceof Error ? e.message : `Failed to execute write: ${msg}`);
       setIsExecuting(false);
     }

116-117: Extract MAX_U64 as a module-level constant.

MAX_U64 is defined identically on lines 116 and 183. Move it to the top of the file with the other constants to avoid duplication.

 const { Write, HostCallResult } = jam_host_calls.general;
 const { Result } = utils;
 type AccountsWrite = jam_host_calls.general.AccountsWrite;
+
+// Maximum u64 value - indicates deletion when used as value pointer
+const MAX_U64 = 0xffffffffffffffffn;

Then remove the local declarations on lines 116 and 183.

src/components/HostCallDialog/handlers/hostCallUtils.ts (2)

113-123: Consider validating hex characters in hexToBytes.

The function validates string length but parseInt with radix 16 will return NaN for invalid hex characters, which becomes 0 when used as a byte. Consider adding validation for invalid characters.

 export function hexToBytes(hex: string): Uint8Array {
   const clean = hex.replace(/^0x/i, "").replace(/\s/g, "");
   if (clean.length % 2 !== 0) {
     throw new Error("Invalid hex string length");
   }
+  if (!/^[0-9a-fA-F]*$/.test(clean)) {
+    throw new Error("Invalid hex characters");
+  }
   const bytes = new Uint8Array(clean.length / 2);
   for (let i = 0; i < clean.length; i += 2) {
     bytes[i / 2] = parseInt(clean.slice(i, i + 2), 16);
   }
   return bytes;
 }

37-56: Line 17 comment is misleading about supporting "proper partial reads"

The MockMemory class stores regions but only returns data if a read is fully contained within a single region. Reads spanning multiple preloaded regions silently return zeros. However, current host call handlers preload only the exact contiguous regions they need and don't perform spanning reads, so this isn't a practical issue. Consider clarifying the comment on line 17 to accurately describe the actual behavior and limitations.

src/store/workers/workersSlice.ts (1)

687-700: Consider error handling if resume execution fails.

After closing the dialog (lines 684-685), if runAllWorkers, stepAllWorkers, or refresh operations fail, the user loses the ability to retry from the dialog. Consider keeping the dialog open until execution succeeds, or providing a way to recover.

One approach is to wrap the resume logic in a try-catch and re-open the dialog on failure:

+    try {
       // Resume execution based on mode
       if (mode === "run") {
         dispatch(setIsRunMode(true));
         await dispatch(runAllWorkers()).unwrap();
       } else if (mode === "block") {
         const stepsToPerform = calculateStepsToExitBlockForAllWorkers(getState() as RootState);
         await dispatch(stepAllWorkers({ stepsToPerform })).unwrap();
       } else {
         // step
         await dispatch(stepAllWorkers({ stepsToPerform: 1 })).unwrap();
       }

       await dispatch(refreshPageAllWorkers());
       await dispatch(refreshMemoryRangeAllWorkers()).unwrap();
+    } catch (error) {
+      // Re-open dialog on failure so user can retry
+      dispatch(setHasHostCallOpen(true));
+      throw error;
+    }
src/store/debugger/debuggerSlice.ts (1)

86-93: Verify the hardcoded spiArgs default value.

The default spiArgs is set to new Uint8Array([0x18, 0x00, 0x00]). Consider adding a comment explaining what this value represents, or extracting it as a named constant in src/types/pvm.ts alongside DEFAULT_REGS and DEFAULT_GAS.

+// Default SPI arguments: 0x180000 (format TBD)
+export const DEFAULT_SPI_ARGS = new Uint8Array([0x18, 0x00, 0x00]);

Then import and use DEFAULT_SPI_ARGS in the initial state.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9897a5e and bc8828a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (37)
  • package.json (1 hunks)
  • src/App.tsx (2 hunks)
  • src/components/DebuggerSettings/Content.tsx (1 hunks)
  • src/components/HostCallDialog/DefaultHostCallContent.tsx (1 hunks)
  • src/components/HostCallDialog/MemoryEditor.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/FetchHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/GasHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/HostCallActionButtons.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/InfoHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/LogHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/ProvideHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/ReadHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/TransferHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/WriteHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/YieldHostCall.tsx (1 hunks)
  • src/components/HostCallDialog/handlers/hostCallUtils.ts (1 hunks)
  • src/components/HostCallDialog/handlers/index.ts (1 hunks)
  • src/components/HostCallDialog/handlers/storageManager.ts (1 hunks)
  • src/components/HostCallDialog/handlers/types.ts (1 hunks)
  • src/components/HostCallDialog/index.tsx (1 hunks)
  • src/components/Instructions/BasicBlocks/CollapsibleInstructionsTable.tsx (2 hunks)
  • src/components/ProgramLoader/Examples.tsx (3 hunks)
  • src/components/ProgramLoader/Loader.tsx (1 hunks)
  • src/components/ProgramLoader/examplePrograms.ts (5 hunks)
  • src/components/ProgramLoader/loadingUtils.ts (3 hunks)
  • src/components/Registers/index.tsx (2 hunks)
  • src/hooks/useDebuggerActions.ts (3 hunks)
  • src/packages/web-worker/command-handlers/index.ts (1 hunks)
  • src/packages/web-worker/command-handlers/memory.ts (1 hunks)
  • src/packages/web-worker/command-handlers/set-memory.ts (1 hunks)
  • src/packages/web-worker/command-handlers/set-state.ts (1 hunks)
  • src/packages/web-worker/types.ts (3 hunks)
  • src/packages/web-worker/worker.ts (1 hunks)
  • src/pages/ProgramLoader.tsx (2 hunks)
  • src/store/debugger/debuggerSlice.ts (6 hunks)
  • src/store/workers/workersSlice.ts (3 hunks)
  • src/types/pvm.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/components/**/*.{ts,tsx}: Keep reusable UI components in src/components/
Write TypeScript-first functional components

Files:

  • src/components/Instructions/BasicBlocks/CollapsibleInstructionsTable.tsx
  • src/components/ProgramLoader/Examples.tsx
  • src/components/HostCallDialog/index.tsx
  • src/components/DebuggerSettings/Content.tsx
  • src/components/HostCallDialog/handlers/storageManager.ts
  • src/components/HostCallDialog/handlers/types.ts
  • src/components/HostCallDialog/handlers/ProvideHostCall.tsx
  • src/components/HostCallDialog/handlers/HostCallActionButtons.tsx
  • src/components/HostCallDialog/handlers/ReadHostCall.tsx
  • src/components/HostCallDialog/handlers/index.ts
  • src/components/HostCallDialog/handlers/TransferHostCall.tsx
  • src/components/HostCallDialog/handlers/LogHostCall.tsx
  • src/components/HostCallDialog/handlers/WriteHostCall.tsx
  • src/components/HostCallDialog/handlers/InfoHostCall.tsx
  • src/components/HostCallDialog/DefaultHostCallContent.tsx
  • src/components/Registers/index.tsx
  • src/components/HostCallDialog/handlers/GasHostCall.tsx
  • src/components/HostCallDialog/handlers/FetchHostCall.tsx
  • src/components/HostCallDialog/handlers/hostCallUtils.ts
  • src/components/HostCallDialog/MemoryEditor.tsx
  • src/components/HostCallDialog/handlers/YieldHostCall.tsx
  • src/components/ProgramLoader/Loader.tsx
  • src/components/ProgramLoader/examplePrograms.ts
  • src/components/ProgramLoader/loadingUtils.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Use two-space indentation in TypeScript files
Use descriptive filenames in kebab-case (e.g., memory-range-panel.tsx)
Validate external inputs with Zod when parsing user data

Files:

  • src/components/Instructions/BasicBlocks/CollapsibleInstructionsTable.tsx
  • src/packages/web-worker/command-handlers/memory.ts
  • src/components/ProgramLoader/Examples.tsx
  • src/components/HostCallDialog/index.tsx
  • src/packages/web-worker/command-handlers/set-state.ts
  • src/components/DebuggerSettings/Content.tsx
  • src/components/HostCallDialog/handlers/storageManager.ts
  • src/components/HostCallDialog/handlers/types.ts
  • src/packages/web-worker/types.ts
  • src/components/HostCallDialog/handlers/ProvideHostCall.tsx
  • src/pages/ProgramLoader.tsx
  • src/components/HostCallDialog/handlers/HostCallActionButtons.tsx
  • src/components/HostCallDialog/handlers/ReadHostCall.tsx
  • src/packages/web-worker/command-handlers/index.ts
  • src/components/HostCallDialog/handlers/index.ts
  • src/packages/web-worker/worker.ts
  • src/components/HostCallDialog/handlers/TransferHostCall.tsx
  • src/packages/web-worker/command-handlers/set-memory.ts
  • src/components/HostCallDialog/handlers/LogHostCall.tsx
  • src/components/HostCallDialog/handlers/WriteHostCall.tsx
  • src/components/HostCallDialog/handlers/InfoHostCall.tsx
  • src/components/HostCallDialog/DefaultHostCallContent.tsx
  • src/components/Registers/index.tsx
  • src/components/HostCallDialog/handlers/GasHostCall.tsx
  • src/store/workers/workersSlice.ts
  • src/components/HostCallDialog/handlers/FetchHostCall.tsx
  • src/types/pvm.ts
  • src/components/HostCallDialog/handlers/hostCallUtils.ts
  • src/components/HostCallDialog/MemoryEditor.tsx
  • src/components/HostCallDialog/handlers/YieldHostCall.tsx
  • src/App.tsx
  • src/components/ProgramLoader/Loader.tsx
  • src/components/ProgramLoader/examplePrograms.ts
  • src/hooks/useDebuggerActions.ts
  • src/components/ProgramLoader/loadingUtils.ts
  • src/store/debugger/debuggerSlice.ts
src/**/*.{css,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Favor Tailwind utilities from globals.css before adding new CSS files

Files:

  • src/components/Instructions/BasicBlocks/CollapsibleInstructionsTable.tsx
  • src/components/ProgramLoader/Examples.tsx
  • src/components/HostCallDialog/index.tsx
  • src/components/DebuggerSettings/Content.tsx
  • src/components/HostCallDialog/handlers/ProvideHostCall.tsx
  • src/pages/ProgramLoader.tsx
  • src/components/HostCallDialog/handlers/HostCallActionButtons.tsx
  • src/components/HostCallDialog/handlers/ReadHostCall.tsx
  • src/components/HostCallDialog/handlers/TransferHostCall.tsx
  • src/components/HostCallDialog/handlers/LogHostCall.tsx
  • src/components/HostCallDialog/handlers/WriteHostCall.tsx
  • src/components/HostCallDialog/handlers/InfoHostCall.tsx
  • src/components/HostCallDialog/DefaultHostCallContent.tsx
  • src/components/Registers/index.tsx
  • src/components/HostCallDialog/handlers/GasHostCall.tsx
  • src/components/HostCallDialog/handlers/FetchHostCall.tsx
  • src/components/HostCallDialog/MemoryEditor.tsx
  • src/components/HostCallDialog/handlers/YieldHostCall.tsx
  • src/App.tsx
  • src/components/ProgramLoader/Loader.tsx
src/packages/web-worker/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep WASM-facing workers in src/packages/web-worker with RPC shapes aligned with integrations listed in README.md

Files:

  • src/packages/web-worker/command-handlers/memory.ts
  • src/packages/web-worker/command-handlers/set-state.ts
  • src/packages/web-worker/types.ts
  • src/packages/web-worker/command-handlers/index.ts
  • src/packages/web-worker/worker.ts
  • src/packages/web-worker/command-handlers/set-memory.ts
src/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep feature views in src/pages/

Files:

  • src/pages/ProgramLoader.tsx
src/store/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep Redux logic in src/store/

Files:

  • src/store/workers/workersSlice.ts
  • src/store/debugger/debuggerSlice.ts
src/{hooks,store}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep stateful flows in hooks or Redux slices

Files:

  • src/store/workers/workersSlice.ts
  • src/hooks/useDebuggerActions.ts
  • src/store/debugger/debuggerSlice.ts
src/{hooks,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Keep shared helpers in src/hooks/ and src/lib/

Files:

  • src/hooks/useDebuggerActions.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: FluffyLabs/pvm-debugger PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T22:06:57.521Z
Learning: Pull requests should summarize intent, list verification steps or commands, and mention any PVM compatibility or worker contract changes
📚 Learning: 2025-11-24T22:06:57.521Z
Learnt from: CR
Repo: FluffyLabs/pvm-debugger PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T22:06:57.521Z
Learning: Applies to src/packages/web-worker/**/*.{ts,tsx} : Keep WASM-facing workers in `src/packages/web-worker` with RPC shapes aligned with integrations listed in `README.md`

Applied to files:

  • src/packages/web-worker/command-handlers/memory.ts
  • src/packages/web-worker/command-handlers/set-state.ts
  • src/packages/web-worker/types.ts
  • src/packages/web-worker/command-handlers/index.ts
  • src/packages/web-worker/worker.ts
  • src/packages/web-worker/command-handlers/set-memory.ts
  • src/store/workers/workersSlice.ts
📚 Learning: 2025-11-24T22:06:57.521Z
Learnt from: CR
Repo: FluffyLabs/pvm-debugger PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T22:06:57.521Z
Learning: Applies to src/**/*.spec.{ts,tsx} : Cover success and failure paths for reducers, hooks, and components that manage debugger state

Applied to files:

  • src/components/ProgramLoader/Examples.tsx
  • src/components/DebuggerSettings/Content.tsx
  • src/packages/web-worker/command-handlers/index.ts
  • src/hooks/useDebuggerActions.ts
  • src/store/debugger/debuggerSlice.ts
📚 Learning: 2025-11-24T22:06:57.521Z
Learnt from: CR
Repo: FluffyLabs/pvm-debugger PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T22:06:57.521Z
Learning: Applies to tests/**/*.spec.ts : Playwright specs in `tests/` should script critical journeys such as uploading WASM or stepping instructions

Applied to files:

  • src/packages/web-worker/command-handlers/index.ts
📚 Learning: 2025-11-24T22:06:57.521Z
Learnt from: CR
Repo: FluffyLabs/pvm-debugger PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T22:06:57.521Z
Learning: Applies to src/components/**/*.{ts,tsx} : Write TypeScript-first functional components

Applied to files:

  • src/components/HostCallDialog/handlers/WriteHostCall.tsx
📚 Learning: 2025-11-24T22:06:57.521Z
Learnt from: CR
Repo: FluffyLabs/pvm-debugger PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T22:06:57.521Z
Learning: Applies to src/**/*.{ts,tsx} : Validate external inputs with Zod when parsing user data

Applied to files:

  • src/components/ProgramLoader/loadingUtils.ts
📚 Learning: 2025-11-24T22:06:57.521Z
Learnt from: CR
Repo: FluffyLabs/pvm-debugger PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T22:06:57.521Z
Learning: Applies to src/{hooks,store}/**/*.{ts,tsx} : Keep stateful flows in hooks or Redux slices

Applied to files:

  • src/store/debugger/debuggerSlice.ts
📚 Learning: 2025-11-24T22:06:57.521Z
Learnt from: CR
Repo: FluffyLabs/pvm-debugger PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T22:06:57.521Z
Learning: Applies to src/store/**/*.{ts,tsx} : Keep Redux logic in `src/store/`

Applied to files:

  • src/store/debugger/debuggerSlice.ts
🧬 Code graph analysis (26)
src/components/Instructions/BasicBlocks/CollapsibleInstructionsTable.tsx (2)
src/packages/pvm/pvm/args-decoder.ts (1)
  • ArgsDecoder (22-203)
src/components/Instructions/utils.tsx (1)
  • decodeAndGetArgsDecoder (39-49)
src/components/ProgramLoader/Examples.tsx (3)
src/components/ProgramLoader/types.ts (1)
  • ProgramUploadFileOutput (3-10)
src/store/hooks.ts (1)
  • useAppSelector (5-5)
src/components/ProgramLoader/loadingUtils.ts (1)
  • loadFileFromUint8Array (42-141)
src/components/HostCallDialog/index.tsx (5)
src/context/NumeralSystemContext.tsx (1)
  • NumeralSystemContext (4-8)
src/components/HostCallDialog/DefaultHostCallContent.tsx (2)
  • MemoryEdit (10-10)
  • DefaultHostCallContent (32-135)
src/store/workers/workersSlice.ts (3)
  • MemoryEdit (629-632)
  • HostCallResumeMode (603-603)
  • resumeAfterHostCall (634-702)
src/types/pvm.ts (2)
  • DEFAULT_REGS (14-14)
  • DEFAULT_GAS (17-17)
src/components/HostCallDialog/handlers/index.ts (1)
  • getHostCallHandler (31-33)
src/packages/web-worker/command-handlers/set-state.ts (3)
src/packages/web-worker/types.ts (1)
  • PvmApiInterface (102-102)
src/types/pvm.ts (1)
  • ExpectedState (47-49)
src/packages/web-worker/utils.ts (2)
  • regsAsUint8 (22-37)
  • getState (11-20)
src/components/DebuggerSettings/Content.tsx (3)
src/context/NumeralSystemContext.tsx (1)
  • NumeralSystemContext (4-8)
src/utils/loggerService.tsx (1)
  • error (39-45)
src/store/debugger/debuggerSlice.ts (1)
  • setSpiArgs (199-201)
src/components/HostCallDialog/handlers/types.ts (2)
src/types/pvm.ts (1)
  • ExpectedState (47-49)
src/store/workers/workersSlice.ts (2)
  • HostCallResumeMode (603-603)
  • MemoryEdit (629-632)
src/packages/web-worker/types.ts (1)
src/types/pvm.ts (1)
  • ExpectedState (47-49)
src/components/HostCallDialog/handlers/ProvideHostCall.tsx (5)
src/components/HostCallDialog/handlers/types.ts (2)
  • HostCallHandlerProps (4-15)
  • HostCallHandler (17-26)
src/types/pvm.ts (1)
  • DEFAULT_REGS (14-14)
src/utils/loggerService.tsx (1)
  • error (39-45)
src/components/HostCallDialog/handlers/hostCallUtils.ts (3)
  • OK (13-13)
  • HostCallContext (155-190)
  • hexToAscii (131-140)
src/components/HostCallDialog/handlers/HostCallActionButtons.tsx (1)
  • HostCallActionButtons (10-27)
src/pages/ProgramLoader.tsx (1)
src/types/pvm.ts (1)
  • DEFAULT_GAS (17-17)
src/components/HostCallDialog/handlers/HostCallActionButtons.tsx (2)
src/store/workers/workersSlice.ts (1)
  • HostCallResumeMode (603-603)
src/components/ui/button.tsx (1)
  • Button (14-19)
src/components/HostCallDialog/handlers/ReadHostCall.tsx (6)
src/components/HostCallDialog/handlers/types.ts (2)
  • HostCallHandlerProps (4-15)
  • HostCallHandler (17-26)
src/components/HostCallDialog/handlers/index.ts (2)
  • HostCallHandlerProps (43-43)
  • HostCallHandler (43-43)
src/types/pvm.ts (1)
  • DEFAULT_REGS (14-14)
src/components/HostCallDialog/handlers/storageManager.ts (2)
  • storageManager (64-64)
  • read (16-19)
src/components/HostCallDialog/handlers/hostCallUtils.ts (3)
  • HostCallContext (155-190)
  • read (37-56)
  • hexToAscii (131-140)
src/components/HostCallDialog/handlers/HostCallActionButtons.tsx (1)
  • HostCallActionButtons (10-27)
src/components/HostCallDialog/handlers/index.ts (9)
src/components/HostCallDialog/handlers/types.ts (1)
  • HostCallHandler (17-26)
src/components/HostCallDialog/handlers/GasHostCall.tsx (1)
  • GasHostCall (99-104)
src/components/HostCallDialog/handlers/FetchHostCall.tsx (1)
  • FetchHostCall (210-215)
src/components/HostCallDialog/handlers/ReadHostCall.tsx (1)
  • ReadHostCall (218-223)
src/components/HostCallDialog/handlers/WriteHostCall.tsx (1)
  • WriteHostCall (294-299)
src/components/HostCallDialog/handlers/InfoHostCall.tsx (1)
  • InfoHostCall (242-247)
src/components/HostCallDialog/handlers/TransferHostCall.tsx (1)
  • TransferHostCall (182-187)
src/components/HostCallDialog/handlers/YieldHostCall.tsx (1)
  • YieldHostCall (158-163)
src/components/HostCallDialog/handlers/ProvideHostCall.tsx (1)
  • ProvideHostCall (176-181)
src/components/HostCallDialog/handlers/TransferHostCall.tsx (3)
src/components/HostCallDialog/handlers/types.ts (2)
  • HostCallHandlerProps (4-15)
  • HostCallHandler (17-26)
src/types/pvm.ts (1)
  • DEFAULT_REGS (14-14)
src/components/HostCallDialog/handlers/hostCallUtils.ts (3)
  • OK (13-13)
  • HostCallContext (155-190)
  • hexToAscii (131-140)
src/packages/web-worker/command-handlers/set-memory.ts (1)
src/packages/web-worker/types.ts (1)
  • PvmApiInterface (102-102)
src/components/HostCallDialog/handlers/LogHostCall.tsx (4)
src/packages/web-worker/goWasmExec.js (1)
  • decoder (194-194)
src/components/HostCallDialog/handlers/types.ts (2)
  • HostCallHandlerProps (4-15)
  • HostCallHandler (17-26)
src/utils/loggerService.tsx (1)
  • error (39-45)
src/components/HostCallDialog/handlers/HostCallActionButtons.tsx (1)
  • HostCallActionButtons (10-27)
src/components/HostCallDialog/handlers/InfoHostCall.tsx (6)
src/components/HostCallDialog/handlers/index.ts (2)
  • HostCallHandlerProps (43-43)
  • HostCallHandler (43-43)
src/types/pvm.ts (1)
  • DEFAULT_REGS (14-14)
src/utils/loggerService.tsx (1)
  • error (39-45)
src/components/HostCallDialog/handlers/hostCallUtils.ts (1)
  • HostCallContext (155-190)
src/components/ui/input.tsx (1)
  • Input (13-13)
src/components/HostCallDialog/handlers/HostCallActionButtons.tsx (1)
  • HostCallActionButtons (10-27)
src/components/Registers/index.tsx (3)
src/packages/web-worker/wasmBindgenInit.ts (1)
  • Status (218-231)
src/lib/utils.ts (1)
  • cn (6-8)
src/packages/ui-kit/DarkMode/utils.ts (1)
  • isDarkMode (5-7)
src/components/HostCallDialog/handlers/GasHostCall.tsx (4)
src/components/HostCallDialog/handlers/index.ts (2)
  • HostCallHandlerProps (43-43)
  • HostCallHandler (43-43)
src/types/pvm.ts (1)
  • DEFAULT_REGS (14-14)
src/components/HostCallDialog/handlers/hostCallUtils.ts (1)
  • HostCallContext (155-190)
src/components/HostCallDialog/handlers/HostCallActionButtons.tsx (1)
  • HostCallActionButtons (10-27)
src/store/workers/workersSlice.ts (4)
src/store/debugger/debuggerSlice.ts (2)
  • setPendingHostCallIndex (190-192)
  • setHasHostCallOpen (187-189)
src/packages/web-worker/utils.ts (1)
  • getState (11-20)
src/store/index.ts (1)
  • RootState (29-29)
src/store/utils.ts (2)
  • asyncWorkerPostMessage (14-38)
  • hasCommandStatusError (40-42)
src/components/HostCallDialog/handlers/hostCallUtils.ts (1)
src/types/pvm.ts (2)
  • DEFAULT_REGS (14-14)
  • DEFAULT_GAS (17-17)
src/App.tsx (1)
src/components/HostCallDialog/index.tsx (1)
  • HostCallDialog (46-198)
src/components/ProgramLoader/Loader.tsx (1)
src/store/debugger/debuggerSlice.ts (1)
  • setSpiArgs (199-201)
src/components/ProgramLoader/examplePrograms.ts (1)
src/types/pvm.ts (1)
  • DEFAULT_GAS (17-17)
src/hooks/useDebuggerActions.ts (1)
src/components/HostCallDialog/handlers/storageManager.ts (1)
  • storageManager (64-64)
src/components/ProgramLoader/loadingUtils.ts (1)
src/types/pvm.ts (1)
  • DEFAULT_GAS (17-17)
src/store/debugger/debuggerSlice.ts (2)
src/types/pvm.ts (3)
  • DEFAULT_REGS (14-14)
  • DEFAULT_GAS (17-17)
  • SpiProgram (6-9)
src/packages/web-worker/wasmBindgenInit.ts (1)
  • Status (218-231)
🔇 Additional comments (42)
src/packages/web-worker/command-handlers/memory.ts (1)

75-96: LGTM! Enhanced error messages improve debuggability.

The dumpParams helper and updated error messages provide valuable context when memory operations fail. The implementation is clean, consistent across all error branches, and will make troubleshooting invalid memory addresses, out-of-bounds ranges, and invalid ranges much easier.

package.json (1)

34-34: Update to @typeberry/lib looks fine; please confirm compatibility

Bumping @typeberry/lib to ^0.4.1-3923458 is reasonable, but since core PVM decoding and host-call behavior depend on it, please confirm the existing test suite (especially program loading and host-call flows) still passes and that no RPC/ABI shapes changed unexpectedly.

src/components/HostCallDialog/handlers/HostCallActionButtons.tsx (1)

1-27: HostCallActionButtons mapping and API look solid

The component cleanly maps the three buttons to "run" | "step" | "block" and centralizes the disabled state, which should make host-call handlers easy to wire. No changes requested.

src/App.tsx (1)

13-13: Root-level HostCallDialog integration is appropriate

Mounting HostCallDialog alongside ToastContainer gives a global, layout-independent host-call UI while actual visibility remains controlled by store state (hasHostCallOpen). This is a good place for the dialog; no changes needed.

Also applies to: 49-49

src/pages/ProgramLoader.tsx (1)

4-4: Use of DEFAULT_GAS for JAM SPI URL loads improves consistency (confirm intended value)

Switching the JAM SPI URL loader to use DEFAULT_GAS instead of a hardcoded 10000n keeps gas initialization aligned with the shared constant from types/pvm. Please just confirm that DEFAULT_GAS (currently 1_000_000n) is the desired starting gas for JAM SPI programs loaded via URL, since this increases the initial budget compared to the previous value.

Also applies to: 77-91

src/types/pvm.ts (1)

13-17: LGTM! Centralized defaults improve consistency.

The introduction of DEFAULT_REGS and DEFAULT_GAS constants is a good practice that standardizes VM initialization across the codebase.

src/packages/web-worker/worker.ts (1)

130-156: LGTM! New command handlers follow established patterns.

The SET_STATE and SET_MEMORY command handlers are implemented consistently with existing command handlers, maintaining the established error handling and response structure.

src/hooks/useDebuggerActions.ts (2)

44-44: LGTM! Storage cleanup on restart is appropriate.

Clearing storage at the start of restartProgram ensures a clean state for host-call interactions.


68-68: LGTM! Storage cleanup on start is appropriate.

Clearing storage at the start of startProgram ensures a clean state for host-call interactions.

src/components/ProgramLoader/Loader.tsx (1)

27-39: The code correctly uses parsed.raw.

The property is consistently used throughout the codebase when accessing the Uint8Array from BytesBlob.parseBlob() results. This pattern is identical in DebuggerSettings/Content.tsx and verified across all usages in the repository.

src/components/DebuggerSettings/Content.tsx (1)

29-42: The code is correct. Throughout the codebase, bytes.BytesBlob.parseBlob() consistently returns an object with a .raw property containing the Uint8Array. This pattern is used identically in multiple files (ProgramLoader.tsx, FetchHostCall.tsx, ProgramTextLoader/index.tsx, loadingUtils.ts, Loader.tsx, and InfoHostCall.tsx), confirming that parsed.raw is the correct property to dispatch.

Likely an incorrect or invalid review comment.

src/components/HostCallDialog/handlers/types.ts (1)

1-26: Well-structured type definitions for host call handlers.

The interfaces are cleanly defined with proper JSDoc documentation and correct type references. The HostCallHandlerProps provides a clear contract for handler components, and HostCallHandler establishes a consistent registry pattern.

src/components/HostCallDialog/handlers/index.ts (2)

43-43: Type re-exports look good.

Proper barrel export pattern for centralizing type access through the handlers module.


12-26: Clean handler registry implementation with efficient O(1) lookup.

The pattern of using an array for ordered registration and a Map for O(1) lookup is appropriate. The Map is constructed once at module load time. Verification confirms all nine handlers have unique indices (0, 1, 3, 4, 5, 20, 25, 26, 100) with no duplicates.

src/components/HostCallDialog/handlers/LogHostCall.tsx (3)

5-35: Log level utilities are well-implemented.

The enum, styles mapping, and helper functions provide clear type-safe handling of log levels with appropriate fallback for unknown values.


53-81: Memory loading effect is well-structured.

The async loading pattern with proper loading/error state management and cleanup is good. The dependency array correctly includes all values used in the effect.


137-142: Verify the host call index 100 for the log handler.

Other handlers use indices in the 0-26 range, but LogHostCall uses index 100. Please verify this matches the actual PVM host call specification for logging.

src/packages/web-worker/command-handlers/index.ts (1)

6-7: Clean integration of new command handlers.

The new runSetState and runSetMemory handlers follow the established pattern and are properly wired into the export. This aligns with the web-worker RPC conventions. As per learnings, this maintains consistency with the WASM-facing worker architecture.

Also applies to: 15-16

src/components/HostCallDialog/handlers/ProvideHostCall.tsx (3)

1-10: Imports and setup look appropriate.

The component properly imports from @typeberry/lib for the Provide host call implementation and related utilities.


35-92: Mount execution with StrictMode guard is correctly implemented.

The hasExecuted ref pattern properly prevents double execution in React StrictMode. The capture mechanism for preimage data through the providePreimage callback is clever.


141-173: UI implementation is clean and well-organized.

The component properly handles loading, error, and data display states. The ASCII preview for smaller preimages (≤256 bytes) is a nice touch for debugging. The action buttons are correctly disabled during loading/execution.

src/components/HostCallDialog/handlers/FetchHostCall.tsx (1)

210-215: LGTM!

The handler structure correctly implements the HostCallHandler interface with appropriate index, name, and component reference.

src/components/HostCallDialog/handlers/InfoHostCall.tsx (1)

242-247: LGTM!

The handler structure correctly implements the HostCallHandler interface with index 5 matching the "info" host call.

src/packages/web-worker/types.ts (1)

43-44: LGTM!

The new SET_STATE and SET_MEMORY commands follow the existing pattern for request/response types. The payload structures are appropriate for their purposes: SET_STATE updates registers and gas, while SET_MEMORY writes data at a specific address.

Also applies to: 69-70, 84-85

src/components/HostCallDialog/index.tsx (3)

82-84: Hardcoded gas deduction of 10 may not match actual host call gas costs.

The fallback gas calculation subtracts 10 unconditionally. Different host calls may have different gas costs. This could lead to incorrect gas tracking.

Is the 10-unit gas deduction intentional as a default/placeholder? If host calls have variable costs, consider making this configurable or documenting the assumption.


140-148: LGTM on modal behavior.

Preventing escape, outside clicks, and hiding the close button is appropriate here since the user must handle the host call to continue PVM execution. The dialog correctly forces interaction.


175-182: Verify that readMemory is passed correctly to custom handler.

Custom handlers receive readMemory but some handlers (like FetchHostCall, InfoHostCall) don't appear to use it in their current implementations. Ensure this prop is intentionally part of the interface for future use or consider making it optional in HostCallHandlerProps.

src/components/HostCallDialog/handlers/ReadHostCall.tsx (1)

218-223: LGTM!

The handler export correctly registers index 3 for the "read" host call with custom UI enabled.

src/components/HostCallDialog/DefaultHostCallContent.tsx (1)

85-134: LGTM!

The two-column layout with gas/registers on the left and memory editor on the right is well-structured and responsive.

src/components/HostCallDialog/handlers/YieldHostCall.tsx (1)

158-163: LGTM!

The handler export correctly registers index 25 for the "yield" host call.

src/components/HostCallDialog/handlers/TransferHostCall.tsx (1)

143-179: LGTM!

The UI clearly displays all transfer data fields (destination, amount, gas, memo) with both hex and ASCII representations for the memo.

src/components/HostCallDialog/handlers/GasHostCall.tsx (2)

26-56: LGTM!

The gas host call implementation is clean and straightforward. The execute-on-mount pattern with hasExecuted ref correctly prevents duplicate execution.


99-104: LGTM!

The handler export correctly registers index 0 for the "gas" host call with custom UI.

src/components/HostCallDialog/handlers/WriteHostCall.tsx (1)

215-291: LGTM!

The render logic is well-structured with clear conditional rendering for different states (loading, error, display). The UI properly handles the delete operation case and provides good user feedback with ASCII previews for smaller values.

src/components/HostCallDialog/handlers/hostCallUtils.ts (2)

77-85: LGTM!

The sub method correctly handles gas underflow by setting gas to 0 and returning true to indicate exhaustion. This aligns with typical PVM gas semantics.


155-189: LGTM!

The HostCallContext class provides a clean abstraction for setting up host call execution environments. It properly initializes mock memory, gas counter, and registers, and the getResult() method provides a unified way to extract the execution outcome.

src/store/workers/workersSlice.ts (3)

266-272: LGTM!

Good fallback behavior when hostCallsTrace is null. Opening the dialog allows users to manually configure the host call response, which is essential for interactive debugging without pre-recorded traces.


605-627: LGTM!

The readMemoryRange thunk correctly reads memory from the first worker and propagates errors appropriately. Using the first worker is consistent with the host call dialog's single-context approach.


664-681: Consider clarifying memory edit semantics across workers before optimizing.

If memory edits can affect shared state visible to other workers or if deterministic replay is required across the system, sequential processing of all workers may be necessary. However, if edits are worker-isolated or order-independent, the current parallel approach is appropriate. Verify whether your use case requires global memory edit ordering.

src/store/debugger/debuggerSlice.ts (3)

110-115: Large instructionCount default may affect UI responsiveness.

The instructionCount has been increased from 1 to 10,000. While this improves execution speed for long programs, it may cause noticeable UI freezes during run mode. Ensure this value is appropriate for the expected use cases.


190-192: LGTM!

The setPendingHostCallIndex reducer is correctly typed with number | null payload, matching the state definition on line 33.


199-201: LGTM!

Good improvement to explicitly type the setSpiArgs payload as Uint8Array, providing better type safety.

tomusdrw and others added 3 commits December 2, 2025 15:31
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@tomusdrw tomusdrw merged commit 192b87e into main Dec 2, 2025
7 checks passed
@tomusdrw tomusdrw deleted the td-host-calls branch December 2, 2025 14:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants