Skip to content

[Draft] Split channel state into immutable/mutable data#1538

Draft
quake wants to merge 2 commits into
developfrom
draft/split-channel-state-immutable-mutable
Draft

[Draft] Split channel state into immutable/mutable data#1538
quake wants to merge 2 commits into
developfrom
draft/split-channel-state-immutable-mutable

Conversation

@quake

@quake quake commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

This is a draft PR showing the direction for reducing serialization overhead in ChannelActorState.

Changes

  • Added ChannelImmutableData struct in fiber-types containing fields that never change after channel opening (pubkeys, fee rates, constraints, etc.)
  • Added CHANNEL_IMMUTABLE_DATA_PREFIX = 208 in store schema
  • Modified insert_channel_actor_state and insert_channel_actor_state_with_pending_commit_diff to write immutable data under a separate prefix on first write only

Next steps (not in this draft)

  • Skip serializing immutable fields in the main ChannelActorData key
  • Use the separate immutable key when reading channel state
  • Add migration for existing records

Why

Each insert_channel_actor_state call serializes ~immutable fields every time state changes, wasting serialization/IO overhead. By storing them once under a separate prefix, these fields can be skipped on subsequent writes.

@quake
quake marked this pull request as draft July 7, 2026 11:22
@chainTe

chainTe commented Jul 8, 2026

Copy link
Copy Markdown

Security Review

Result: 2 confirmed finding(s), both low severity (design-stage feedback for this draft)
Reviewed range: a96022ef..4860b735 (develop..draft/split-channel-state-immutable-mutable)

Validation:

  • Existing broad tests were not run locally; CI is expected to cover them.
  • Findings were validated by focused code tracing; the new CHANNEL_IMMUTABLE_DATA_PREFIX keyspace has no reader in this diff, so there is no runtime behavior to exercise yet.

Findings:

  1. Low — the write-once "immutable" snapshot captures fields that are still mutable at first persist. The [208]+channel_id record is frozen by the self.get(&immutable_key).is_none() guards (store_impl/mod.rs), but the first insert_channel_actor_state happens during NegotiatingFunding (end of every handled message), before funding_tx stops mutating (TX collaboration) and before funding_tx_confirmed_at is set at on-chain confirmation (channel.rs:3313). For the initiator, id also changes in fill_in_channel_id after AcceptChannel, and move_channel_actor_state neither deletes [208]+temp_id nor writes [208]+final_id. So the stored record is stale (usually funding_tx mid-negotiation, funding_tx_confirmed_at: None) for normally opened channels. Harmless today since nothing reads it — but the stated next step (serving channel-state reads from this key) would turn this into corrupted restored channel state (lost funding tx/confirmation → reestablishment/settlement/watchtower breakage). Suggest either restricting the struct to fields truly fixed at channel creation (drop funding_tx, funding_tx_confirmed_at, id), or keying the write-once moment to funding confirmation instead of first persist, plus handling the id transition in move_channel_actor_state and adding the planned migration before any read path lands.

  2. Low — prefix-208 records are never deleted and retain channel key material. The record includes signer: InMemorySigner (funding/TLC/musig2 private keys + commitment_seed), but delete_channel_actor_state and move_channel_actor_state don't remove [208]+id. After channel deletion (e.g. abandon/abort-funding via the network actor) a logical copy of the channel's key material now persists in the DB and in backups indefinitely, and external-funding id transitions orphan an extra [208]+temp_id record. Suggest deleting the record in both lifecycle functions, and reconsidering whether signer belongs in the split-out record at all.

Notes:

  • Prefix 208 is unique across the schema (including watchtower/CCH prefixes) and check_validate tolerates the new keyspace; the new put shares the batch with the main state write, so no crash-atomicity regression.

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