Skip to content

fix(node): adapt devnet Terminal RPC module to the CKB version - #477

Open
humble-little-bear wants to merge 1 commit into
developfrom
agent/claude-bear/2533cc01-terminal-rpc-compat
Open

fix(node): adapt devnet Terminal RPC module to the CKB version#477
humble-little-bear wants to merge 1 commit into
developfrom
agent/claude-bear/2533cc01-terminal-rpc-compat

Conversation

@humble-little-bear

Copy link
Copy Markdown
Collaborator

Problem

The devnet ckb.toml template enables the Terminal RPC module, which only exists since CKB v0.205.0 (nervosnetwork/ckb#4989). For anyone running the devnet with an older CKB (offckb node <旧版本>, a pinned defaultCKBVersion, or --binary-path), the node aborts at startup with an opaque serde error:

unknown variant `Terminal`, expected one of `Net`, `Pool`, ...

Worse, migrateLegacyDevnetRpcConfig re-added Terminal on every offckb node start, so manually removing it from the config didn't help — an unbreakable crash loop that documentation alone could not fix.

What this PR does

Node startup now resolves the effective CKB version (managed binaries know it by construction; a custom --binary-path is probed via the existing getVersionFromBinary()) and adapts:

  1. Fresh chains for a pre-0.205.0 binary are initialized from the template with Terminal stripped (tcp_listen_address predates 0.205.0 and stays), with a log line noting the offckb status panels need ≥ 0.205.0.
  2. The legacy-config migration no longer re-adds Terminal for such binaries — breaking the remove/re-add loop — while still enabling tcp_listen_address.
  3. Existing config with Terminal + old binary fails fast before spawning CKB, with an actionable error naming the file, the required version, and the two remedies — replacing the serde dump.
  4. Unprobeable custom binaries keep the historical behavior (assume support); if such a binary then crashes with the tell-tale unknown variant Terminal`` stderr, the startup error now appends a hint pointing at the actual cause (bounded 4 KB stderr tail).
  5. README's status section notes the CKB >= 0.205.0 requirement for the TUI's system-metric panels.

Pre-existing user configs are never silently rewritten — the strip applies only to a pristine, freshly copied template; everything else surfaces as a clear error.

Test plan

  • pnpm test — 29 suites, 237 passed (21 in init-chain, 9 new in node-terminal-rpc covering version gating, fail-fast, probe fallback, and the stderr hint)
  • tsc --noEmit clean, eslint clean, pnpm build succeeds
  • Strip path verified against the real bundled template (fresh init with 0.120.0 produces a valid ckb.toml without Terminal, with tcp_listen_address intact)

🤖 Generated with Claude Code

The devnet ckb.toml template enables the Terminal RPC module, which only
exists since CKB v0.205.0 (nervosnetwork/ckb#4989). Older binaries abort
at startup with an opaque serde "unknown variant `Terminal`" error, and
migrateLegacyDevnetRpcConfig re-added the module on every `offckb node`
start even after users removed it by hand — an unbreakable crash loop for
anyone pinned to an old CKB.

- initChainIfNeeded takes the effective CKB version: fresh chains for a
  pre-0.205.0 binary are initialized from the template with Terminal
  stripped (tcp_listen_address, which predates 0.205.0, stays), and the
  legacy-config migration no longer re-adds Terminal for such binaries.
- nodeDevnet resolves the effective version (managed binaries know it;
  a custom --binary-path is probed via getVersionFromBinary) and fails
  fast with an actionable error when the existing config enables Terminal
  but the binary is too old, instead of letting CKB dump the serde error.
- A custom binary whose version cannot be probed keeps the historical
  behavior; if it then crashes with the tell-tale "unknown variant
  `Terminal`" stderr, the startup error now points at the actual cause.
- README's status section notes the CKB >= 0.205.0 requirement for the
  TUI's system-metric panels.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Fixed devnet startup failures when using CKB binaries older than 0.205.0.
    • Automatically adapts Terminal RPC configuration for the selected CKB version.
    • Added actionable error guidance for incompatible Terminal RPC configurations.
    • Prevented legacy configuration migration from repeatedly re-enabling unsupported modules.
  • Documentation

    • Clarified that system-metric panels require CKB 0.205.0 or newer.
    • Documented the reduced panel availability when using older binaries.

Walkthrough

Devnet startup now detects the selected CKB version, gates the Terminal RPC module in generated configurations, prevents incompatible legacy migration, and reports actionable errors for unsupported configurations or Terminal-related startup failures. Documentation and tests cover the new behavior.

Changes

Terminal RPC compatibility

Layer / File(s) Summary
Version-gated devnet configuration
src/node/init-chain.ts, tests/init-chain.test.ts
Initialization removes Terminal from fresh configurations for unsupported CKB versions, preserves existing configurations, and prevents legacy migration from re-adding the module.
Startup validation and diagnostics
src/cmd/node.ts, tests/node-terminal-rpc.test.ts, tests/node-supervisor.test.ts, .changeset/..., README.md
Startup forwards the effective binary version, fails fast on incompatible configurations, captures stderr for Terminal-specific hints, and documents the CKB version requirement.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant nodeDevnet
  participant CKBBinary
  participant initChainIfNeeded
  participant CKBDevnet
  nodeDevnet->>CKBBinary: probe or select CKB version
  nodeDevnet->>initChainIfNeeded: initialize ckb.toml with ckbVersion
  initChainIfNeeded-->>nodeDevnet: version-compatible configuration
  nodeDevnet->>CKBDevnet: spawn devnet with ckb.toml
  CKBDevnet-->>nodeDevnet: readiness or stderr result
Loading

Possibly related PRs

Suggested reviewers: retricsu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: making devnet Terminal RPC handling depend on the CKB version.
Description check ✅ Passed The description is detailed and directly matches the changeset, covering version-aware Terminal RPC handling and related fixes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
tests/init-chain.test.ts (1)

209-330: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

LGTM! Solid coverage of the version-gating matrix (unknown/old/new versions × fresh-init/migration/pre-existing-config paths).

One minor gap: removeTerminalModule's multi-line-array branch (init-chain.ts Lines 166-174) is never exercised — the bundled template being stripped in these tests is single-line, and the multi-line fixture here is only used to assert "never edit an existing file," not fresh-init stripping. Consider adding a case where the bundled template itself is (or is rewritten to) multi-line before init, if that branch is meant to be reachable in practice.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/init-chain.test.ts` around lines 209 - 330, Add coverage for the
multi-line-array branch in removeTerminalModule by making the fresh-init
template’s RPC modules multi-line before invoking initChainIfNeeded with an old
CKB version. Assert Terminal is removed while other modules remain, ensuring
this path tests actual template stripping rather than preservation of an
existing ckb.toml.
src/node/init-chain.ts (1)

146-197: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use TERMINAL_RPC_MODULE instead of the hardcoded "Terminal" literal.

removeTerminalModule's regexes (Lines 158-160, 168) hardcode the string "Terminal" even though TERMINAL_RPC_MODULE already exists as the canonical constant (used elsewhere in this file, e.g. devnetConfigHasTerminalRpc, addTerminalModule). If the module name ever changes, these regexes would silently stop matching.

♻️ Proposed fix
   if (lines[modulesStart].includes(']')) {
     const line = lines[modulesStart];
     // Terminal last (the bundled template), Terminal first, or Terminal alone.
-    let updated = line.replace(/,\s*"Terminal"/, '');
-    if (updated === line) updated = line.replace(/"Terminal"\s*,\s*/, '');
-    if (updated === line) updated = line.replace(/\[\s*"Terminal"\s*\]/, '[]');
+    let updated = line.replace(new RegExp(`,\\s*"${TERMINAL_RPC_MODULE}"`), '');
+    if (updated === line) updated = line.replace(new RegExp(`"${TERMINAL_RPC_MODULE}"\\s*,\\s*`), '');
+    if (updated === line) updated = line.replace(new RegExp(`\\[\\s*"${TERMINAL_RPC_MODULE}"\\s*\\]`), '[]');
     if (updated === line) return false;
     lines[modulesStart] = updated;
     return true;
   }

   // Multi-line array: drop the line holding the Terminal entry.
   for (let i = modulesStart + 1; i < section.end; i++) {
-    if (/^\s*"Terminal",?\s*$/.test(lines[i])) {
+    if (new RegExp(`^\\s*"${TERMINAL_RPC_MODULE}",?\\s*$`).test(lines[i])) {
       lines.splice(i, 1);
       return true;
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/node/init-chain.ts` around lines 146 - 197, Update removeTerminalModule
to derive all Terminal-entry matching and replacement patterns from the existing
TERMINAL_RPC_MODULE constant instead of hardcoding "Terminal". Preserve the
current handling for single-line and multi-line module arrays, including quoted
TOML entries.
src/cmd/node.ts (1)

71-109: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider validating Terminal compatibility before installCKBBinary, not after.

For the managed-binary path, effectiveCkbVersion is already known as ckbVersion before installCKBBinary runs — nothing about the compatibility check (Lines 96-108) actually depends on the binary being installed or the chain being initialized first. Moving the devnetConfigHasTerminalRpc/supportsTerminalRpcModule check earlier would fail fast without a potentially slow binary download when the run is going to error out anyway.

[reliability_and_resilience]

♻️ Proposed reordering
   const settings = readSettings();
   const ckbVersion = version || settings.bins.defaultCKBVersion;
   let ckbBinPath = '';
   let effectiveCkbVersion: string | null = null;
+  const devnetConfigPath = settings.devnet.configPath;

   if (binaryPath) {
     ckbBinPath = binaryPath;
     logger.info(`Using custom CKB binary path: ${ckbBinPath}`);
     effectiveCkbVersion = getVersionFromBinary(ckbBinPath);
   } else {
-    await installCKBBinary(ckbVersion);
-    ckbBinPath = getCKBBinaryPath(ckbVersion);
     effectiveCkbVersion = ckbVersion;
   }
-  await initChainIfNeeded({ ckbVersion: effectiveCkbVersion });
-  const devnetConfigPath = settings.devnet.configPath;

-  if (!supportsTerminalRpcModule(effectiveCkbVersion) && devnetConfigHasTerminalRpc(devnetConfigPath)) {
+  const terminalSupported = supportsTerminalRpcModule(effectiveCkbVersion);
+  if (!terminalSupported && devnetConfigHasTerminalRpc(devnetConfigPath)) {
     throw new Error(/* ... */);
   }
-  if (!supportsTerminalRpcModule(effectiveCkbVersion)) {
+  if (!terminalSupported) {
     logger.info(/* ... */);
   }
+
+  if (!binaryPath) {
+    await installCKBBinary(ckbVersion);
+    ckbBinPath = getCKBBinaryPath(ckbVersion);
+  }
+  await initChainIfNeeded({ ckbVersion: effectiveCkbVersion });

Category note: this doubles as for the supportsTerminalRpcModule de-duplication.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cmd/node.ts` around lines 71 - 109, Move the Terminal compatibility
validation using devnetConfigHasTerminalRpc and supportsTerminalRpcModule before
installCKBBinary in the managed-binary path, using the already-known ckbVersion
as the selected version. Preserve the existing error message and logging
behavior, avoid duplicating the validation after initialization, and retain the
custom-binary path’s probed-version validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/cmd/node.ts`:
- Around line 71-109: Move the Terminal compatibility validation using
devnetConfigHasTerminalRpc and supportsTerminalRpcModule before installCKBBinary
in the managed-binary path, using the already-known ckbVersion as the selected
version. Preserve the existing error message and logging behavior, avoid
duplicating the validation after initialization, and retain the custom-binary
path’s probed-version validation.

In `@src/node/init-chain.ts`:
- Around line 146-197: Update removeTerminalModule to derive all Terminal-entry
matching and replacement patterns from the existing TERMINAL_RPC_MODULE constant
instead of hardcoding "Terminal". Preserve the current handling for single-line
and multi-line module arrays, including quoted TOML entries.

In `@tests/init-chain.test.ts`:
- Around line 209-330: Add coverage for the multi-line-array branch in
removeTerminalModule by making the fresh-init template’s RPC modules multi-line
before invoking initChainIfNeeded with an old CKB version. Assert Terminal is
removed while other modules remain, ensuring this path tests actual template
stripping rather than preservation of an existing ckb.toml.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 598c041d-d5e1-4eed-9117-50e10791b9d7

📥 Commits

Reviewing files that changed from the base of the PR and between 920ef4d and 9b2e211.

📒 Files selected for processing (7)
  • .changeset/terminal-rpc-version-compat.md
  • README.md
  • src/cmd/node.ts
  • src/node/init-chain.ts
  • tests/init-chain.test.ts
  • tests/node-supervisor.test.ts
  • tests/node-terminal-rpc.test.ts

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.

1 participant