feat(core): allow serialization of SyncResponse#2232
Open
evanlinjin wants to merge 1 commit into
Open
Conversation
Add `serde::Serialize`/`Deserialize` for `SyncResponse` so a connected device can serialize a sync response and hand it to an air-gapped device to apply independently. `SyncResponse` holds a `TxUpdate` and an `Option<CheckPoint>`: - `TxUpdate` gains a plain derive; its fields are flat collections so there is nothing self-referential to recurse over. - `CheckPoint` is a reference-counted linked list, so a derived impl would recurse through `prev`/`skip` once per checkpoint and overflow the stack on long chains -- the same hazard that forced the hand-written `Drop` (bitcoindevkit#1634). It is instead serialized iteratively as a flat sequence of `(height, data)` pairs and rebuilt with `CheckPoint::from_blocks`, which re-derives the `skip`/`index` topology deterministically. Tests cover round-tripping `CheckPoint`, `TxUpdate` and `SyncResponse`, and assert (de)serialization is not recursive by round-tripping a long chain on a deliberately small thread stack. https://claude.ai/code/session_014BXMFRQP8qoGBghJcWzakG
3 tasks
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2232 +/- ##
==========================================
+ Coverage 77.69% 79.11% +1.42%
==========================================
Files 29 30 +1
Lines 5801 6047 +246
Branches 271 279 +8
==========================================
+ Hits 4507 4784 +277
+ Misses 1223 1187 -36
- Partials 71 76 +5
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds
serde::Serialize/serde::DeserializeforSyncResponse, enabling air-gapped workflows: a connected (online) device can sync, serialize theSyncResponse, and hand it to a disconnected (offline) device which deserializes and applies it independently. This is the goal of #1954, implemented without recursion.SyncResponseis made up of aTxUpdateand anOption<CheckPoint>, so both gain serde support:TxUpdate— a plain#[derive(Serialize, Deserialize)]. Its fields are flat collections, so there is nothing self-referential to recurse over. AnOrdbound is added onAfor deserialization so thatanchors: BTreeSet<(A, Txid)>can be rebuilt.CheckPoint— this is the interesting one. ACheckPointis a reference-counted linked list (prev+skippointers), so a derived implementation would recurse one stack frame per checkpoint and overflow the stack on long chains — the exact hazard that already forced a hand-writtenDrop(example_bitcoind_rpc_pollingsync command ends with stack overflow #1634). It is therefore implemented by hand:CheckPoint::iter()and emit a flat sequence of(height, data)pairs.CheckPoint::from_blocks(..), which re-derives theskip/indextopology deterministically.The
skip/indextopology is intentionally not serialized — it is reconstructed on load, keeping the encoding minimal and both directions iterative.Notes to the reviewers
CheckPoints is a bit odd since it is a linked list" concern raised in review: the linked list is flattened to a(height, data)sequence and rebuilt, so neither serialization nor deserialization recurses.checkpoint_serde_is_not_recursiveround-trips a 10k-checkpoint chain on a deliberately small (128 KiB) thread stack, mirroring the existingcheckpoint_drop_is_not_recursivetest — a recursive impl would overflow it.serde_jsonis added only as a dev-dependency ofbdk_core, for the round-trip tests.SyncResponseto match core: allow serialization of SyncResponse #1954.FullScanResponsecan follow the exact same pattern as a trivial follow-up if desired.Changelog notice
serde::Serializeandserde::Deserializeimplementations forSyncResponse,TxUpdate, andCheckPoint(under theserdefeature).CheckPointis (de)serialized iteratively as a flat list of(height, data)blocks to avoid recursing over its linked-list structure.Checklists
All Submissions:
New Features:
Generated by Claude Code