I’ve been working on a small experiment called CKB Script Port .
The idea is to see whether already-synced state for one CKB Script can be moved from one light-client installation to another, so the new installation does not always have to rebuild the same Script history from scratch.
I first tested this with Pocket Node, and later with iBytes.
While testing the iBytes setup, I ran into an interesting light-client case.
A Script can be synced up to a certain block height even when the light-client database does not have the exact block hash for that height stored locally.
That matters for Script Port because if I want another light client to continue from that point, I need a boundary I can actually verify. I didn’t want to solve that by simply trusting a hash from an external RPC.
So I tested using the light client’s existing block-proof verification path to verify that historical block instead.
That worked, and I was able to complete the handoff on the iBytes setup and continue syncing from the next block.
The Script Port repo is here:
Contribute to Ticoworld/ckb-script-port development by creating an account on GitHub.
The historical-header part also became an upstream ckb-light-client contribution:
develop ← Ticoworld:verified-historical-header-lookup-v2
opened 07:50AM - 02 Oct 26 UTC
## Summary
Adds an API to verify a historical block header using the light cl… ient's existing block-proof verification path.
A caller provides a block number and candidate header hash. The light client verifies that candidate against the chain state it currently accepts before reporting the request as verified.
Historical requests are tracked separately from ordinary `fetch_header` requests, so they do not change existing fetch behavior.
## Motivation
A caller may already know a historical header hash but still need the light client to verify that it belongs to the accepted chain.
Using `fetch_header(hash)` alone is not enough for this use case because a header may already exist in local cache from earlier work.
This change lets callers explicitly request fresh proof-backed verification of a historical `(block number, hash)` pair.
## Related work
PR [#292](https://github.com/nervosnetwork/ckb-light-client/pull/292) adds height binding for filter-matched block hashes inside the synchronization path.
This PR uses the same existing block-proof verification machinery, but exposes a separate caller-driven historical verification request for an explicit `(block_number, candidate_hash)` pair.
Unlike the filter-sync path, a new historical request is not satisfied by a cached header alone and becomes stale if the accepted chain tip changes before completion.
## Design
- adds `request_historical_header_proof(...)`
- adds `poll_historical_header_proof(...)`
- uses the existing `GetBlocksProof` verification logic
- treats the supplied candidate hash as untrusted until proof verification succeeds
- ties verification to the accepted tip captured when the request starts
- reports the request as stale if that accepted tip changes
- does not allow a cached header alone to satisfy a new historical verification request
- keeps historical request state separate from ordinary `fetch_header` state
- uses the existing verified-header storage path
- adds no new wire protocol or storage schema
## Validation
- `cargo fmt --all -- --check`
- `make clippy`
- `make test`
Result: **145 tests passed**.
Additional tests cover:
- successful historical-header verification
- missing-header handling
- isolation from ordinary `fetch_header` requests
- mixed ordinary and historical requests
- timeout and disconnect retry
- accepted-tip changes during a request
- cached headers not satisfying a new verification request
- the full public API → scheduler → proof verification → polling path
I’m still treating Script Port as an experiment, not as something every wallet necessarily needs.
But this was one of the more interesting things I found while testing the idea, so I thought it was worth sharing.
The CKBuilder discussion is here too:
opened 09:12AM - 11 Sep 26 UTC
## Project Summary
CKB Script Port is a Rust library for moving already-synced … data for one CKB Script from one light-client install to another.
The idea is simple:
If one install has already processed the history for a Script, another install should not always need to repeat that same historical work from scratch.
CKB Script Port lets the already-synced Script data be exported, imported into another install, and then normal syncing can continue from the next block.
Repository:
https://github.com/Ticoworld/ckb-script-port
---
## Why I Built It
A wallet or application may already have spent time syncing the history for a Script.
If another installation needs the same Script state, it may have to rebuild that history again.
I wanted to test a narrower alternative:
> Can already-synced data for one Script be moved safely to another light-client installation without copying the whole database?
The new installation should still remain responsible for normal chain verification and future syncing.
---
## How It Works
old install
↓
export already-synced Script data
↓
portable artifact
↓
new install
↓
import
↓
continue from the next block
The current implementation works with one exact CKB Script at a time.
It moves the Script-related state and the transaction data needed by that state.
It does not move wallet keys, mnemonics, the whole light-client database, or application caches.
---
## What Works Today
The current prototype can:
- export state for one exact lock or type Script;
- include the transaction data required by that state;
- validate the exported data before import;
- import it atomically into the destination;
- work with RocksDB and SQLite;
- move state across the supported storage backends;
- continue syncing after the imported point.
The supported light-client storage layouts are deliberately pinned. I am not claiming arbitrary-version compatibility.
---
## Pocket Reference Test
I used Pocket Node as a real reference application to test whether this works outside my own fixtures.
Pocket has not requested, adopted, or endorsed this project.
The test used:
- Pocket Node v1.8.3;
- Pocket's embedded CKB light-client SQLite state;
- a real ARM64 Android device;
- one real registered lock Script;
- a fresh destination state.
The source had already processed that Script through block:
`22,370,055`
After importing the Script state, the destination's first new filter request started at:
`22,370,056`
which is the next block.
A later matching transaction was then processed normally, and the resulting state remained usable after Pocket was stopped and restarted.
As a comparison, the clean control without the imported state started filtering from the older configured historical range.
The Pocket reference evidence is here:
https://github.com/Ticoworld/ckb-script-port/blob/master/docs/G3_FINAL_REFERENCE_PRODUCT_CHECKPOINT.md
---
## What This Shows
For the tested Pocket/light-client setup, already-synced state for one Script could be moved to a fresh destination and reused instead of rebuilding that same accepted range again.
What I do not know yet is whether this is useful enough to exist as a reusable CKB component.
That is the main reason I am opening this issue now.
---
## What It Does Not Do
CKB Script Port is not:
- wallet backup or recovery;
- mnemonic or private-key migration;
- full light-client database backup;
- application-cache migration;
- proof of arbitrary historical completeness;
- arbitrary-version migration;
- multi-Script atomic migration;
- a universal performance improvement;
- a Pocket production integration.
If the original local state has already been lost, normal recovery and resync are still required.
And if somebody simply wants to clone an entire same-version installation, copying the whole database may be simpler.
The specific problem I am testing is narrower:
> Can already-synced data for one Script be reused on another install?
---
## Why I Am Asking for Feedback Now
The prototype has reached the point where I do not want to keep adding features based only on my own assumptions.
I have paused further scope expansion while I get feedback on whether this responsibility itself makes sense.
The main question is where this kind of functionality belongs, if it is useful at all:
- a separate reusable library;
- `ckb-light-client` itself;
- individual applications that need migration;
- or nowhere, because an existing mechanism already handles the problem better.
---
## Feedback I Would Appreciate
1. Is reusing already-synced Script data between light-client installations a useful problem to solve?
2. Does this make sense as a reusable library, or should applications handle it themselves?
3. Would this fit better inside `ckb-light-client`?
4. Is one exact Script per handoff a reasonable starting point?
5. Is there already a more natural CKB/light-client way to achieve the same result?
6. What evidence would you want to see next before considering this worth continuing?
I am especially interested in criticism of the boundary itself.
If this belongs somewhere else, or if existing CKB mechanisms already solve it more cleanly, I would rather find that out now before building more.
---
## Current Status
Repository:
https://github.com/Ticoworld/ckb-script-port
Development is currently paused while I collect feedback.
I am not treating the current result as proof of ecosystem demand or preparing a funding proposal from it yet.
5 Likes
Jnr6
October 5, 2026, 10:45am
2
Did you hit any issue when testing with Pocket Node.
1 Like
Not really on Pocket itself. The Pocket test actually went pretty smoothly once I got into the light-client state.
I was able to move the Script state to a fresh install, continue from the next block, and it still worked after restart.
The weird issue came later when I tested with iBytes, not Pocket.
1 Like
Jnr6
October 5, 2026, 11:06am
4
Thank you, I’ll look more into it and this will be one of the features to introduce down the line
2 Likes
That’s great to hear, thanks bro. I’ll keep you posted as the upstream side moves.
will really make sense if syncs on new devices/installs can continue from where the last install stopped without having to do it all over from scratch. excited for your next update.
1 Like