Skip to content

offckb logs script returns empty output despite contract debug logs in run.log #513

Description

@sunchengzhu

Summary

After a successful contract call on a local devnet, offckb logs script --tail 20 returns no output and exits with code 0, even though the node's run.log already contains the contract's debug messages.

The script-log filter expects the target ckb-script, but the tested CKB versions emit these messages under ckb_script::verify. As a result, OffCKB filters out the actual contract output.

Environment

  • @offckb/cli: 0.4.13, npm release; verified with offckb --version.
  • CKB: reproduced with 0.207.0 and 0.208.0. The latter is the default CKB version configured by this OffCKB release; both runs explicitly selected a local binary with --binary-path.
  • Node.js: 20.17.0.
  • OS: macOS 26.6.2, arm64.
  • Local devnet running in daemon mode, with isolated OffCKB directories.
  • The bundled logger configuration was unchanged: filter = "info,ckb-script=debug".

Reproduction

  1. Start a devnet and create a TypeScript project:

    offckb node --daemon --binary-path /path/to/ckb
    offckb create log-demo --no-interactive --language typescript \
      --manager pnpm --contract-name diagnostic-contract --no-install --no-git
    cd log-demo
  2. Make contracts/diagnostic-contract/src/index.ts emit identifiable debug messages:

    import * as bindings from '@ckb-js-std/bindings';
    
    bindings.debug('OFFCKB_DIAGNOSTIC_FIRST');
    bindings.debug('OFFCKB_DIAGNOSTIC_SECOND');
    bindings.exit(0);
  3. Build and deploy it using a funded devnet signer:

    pnpm install
    pnpm run build
    pnpm run deploy --network devnet --yes
  4. Submit a transaction that executes the deployed contract through the OffCKB RPC proxy and wait until get_transaction reports committed.

    In the reproduced run, a public CCC SDK client signed a transaction using the JS VM as an output type script, referencing the deployed bytecode and generated system-script dependencies. The transaction was submitted to http://127.0.0.1:28114 with send_transaction(transaction, "passthrough").

  5. After the messages appear in <devnet.dataPath>/logs/run.log, run:

    offckb logs script --tail 20

    devnet.dataPath is available through offckb config list.

Actual Result

The command returns empty stdout and stderr, with exit code 0.

The node log already contains the contract output. One actual entry from the CKB 0.208.0 run, which used a unique marker, is:

2026-09-11 11:20:02.169 +00:00 GlobalRt-10 DEBUG ckb_script::verify  script group: Byte32(0xafa75b18ff86fe7e188169be16b3279833ceeb197b0d14abf23ff2b005199f8d) DEBUG OUTPUT: OFFCKB_DIAGNOSTIC_19f360119a504c10af02b4d395832def_FIRST

The entire log contained only 78 lines, so this was not caused by the script-log scan window being too small. The transaction had committed, and the command was invoked while the daemon was still running.

The node, miner and RPC log targets returned their corresponding real log records; filtering RPC logs by this transaction's hash also worked.

Expected Result

offckb logs script should display the contract's debug messages from the running devnet, while excluding unrelated node records. Users should be able to find their contract output without locating and inspecting OffCKB's internal log files.

Initial Analysis

In the source corresponding to this release:

The actual records have target ckb_script::verify and contain DEBUG OUTPUT:, so they fail that exact-match filter and are discarded.

The configured ckb-script=debug filter still enables these records: in both tested CKB versions, convert_compatible_crate_name() keeps the original filter directive and adds its underscore variant, ckb_script=debug. The logger then writes and forwards the original record.target(), without renaming it. This explains why the messages reach run.log with target ckb_script::verify, even though the configuration uses ckb-script.

The reproduced failure above covers reading existing script logs while the daemon is running. The --follow and live console-forwarding paths have the same filtering problem according to source inspection, but were not independently exercised in this run.

Suggested Fix

Update both src/cmd/logs.ts and src/cmd/node.ts to use a shared script-debug record classifier. Apply it consistently to historical log reading, --follow, and live console forwarding, including the file-filtering helper used by historical reads.

Match the actual ckb_script module path and its submodules, preserving the module boundary:

target === 'ckb_script' ||
target.startsWith('ckb_script::')

A bare target.startsWith('ckb_script') also matches unrelated names such as ckb_script_other. For ckb_script module records, additionally recognize the contract-debug message marker DEBUG OUTPUT: so unrelated CKB verification logs are not presented as contract output. Checking only level === 'DEBUG' does not establish that a message came from a contract. Preserve continuation lines for multiline contract output.

Regression fixtures should use captured real records, including ckb_script::verify and script group: Byte32(0x...) DEBUG OUTPUT: .... Tests using only the synthetic ckb-script / script group: 0xabcd format cannot detect this mismatch. Include unrelated verification records as negative examples.

Retain a regression test that invokes a real contract and checks its unique debug messages, and validate all three paths after the fix:

  • offckb logs script, including typical --tail and --grep usage.
  • offckb logs script --follow when the contract emits new messages.
  • Live contract-output forwarding in the foreground offckb node console.

Impact

The basic contract-log troubleshooting workflow is unusable in the tested environments: a successful command with empty output makes existing contract diagnostics invisible to the user.

Source inspection also indicates that the foreground offckb node console's CKB-Script: live output is likely affected by the same exact-match condition. This additional impact still needs independent runtime verification; both command paths should be fixed together.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions