Skip to content

Is VssStore intentionally opting out of VSS conditional writes and rollback detection? #1090

Description

@hash-money

We use ldk-node through orange-sdk for seed-based recovery of live Lightning channel state. We re-read the pinned revision 0cea341 (2026-07-20) before proposing changes, and re-checked main at c309ccd (2026-09-04), where the same code is at src/io/vss_store.rs:568-579 (put) and :614 (delete). We would first like to confirm the intended VSS threat/concurrency model.

At this revision, ordinary writes set vss_version = -1, send global_version: None, and put KeyValue.version = -1 (src/io/vss_store.rs:558-574). Schema initialization does the same (:881-901), and deletes use version: -1 (:590-608).

vss-client-ng 0.6.0 defines -1 as a non-conditional write which resets the key version to 1, while an absent global_version omits the store-wide equality check (src/types.rs:48-96).

Static measurement: all three mutation constructors we found—ordinary put, schema put, and delete—are unconditional. The read path also discards both the returned KeyValue.version and decrypted PlaintextBlob.version (src/io/vss_store.rs:508-543); list paths discard key versions and global_version (:478-505,681-724).

The in-process next_version counter only orders callbacks (:177-190,727-753) and resets on restart, so it does not prevent a restored device or second process from blindly overwriting newer state.

For new stores, schema V1 authenticates the obfuscated key as AAD (:59-73,539-564,881-909), but a previous ciphertext for the same key still decrypts. A coherent old manager/monitor set can therefore pass local startup reconciliation; LDK’s data-loss-protect catches it later on peer reconnect, but a stale commitment broadcast before then remains unsafe.

Is this intentional—i.e. is VssStore currently designed for a trusted, single-writer VSS service, with concurrent instances and server rollback out of scope? Is the encrypted PlaintextBlob.version intended to be checked by integrations such as ldk-node?

Our concrete need is safe new-device restore when the old instance may still run. KVStore exposes no versions to orange-sdk, so addressing this outside VssStore requires carrying a wrapper/fork and still cannot make ldk-node’s own writes conditional.

If blind mode is not intentional, would you accept a PR that:

  • initializes a per-key version cache from ListKeyVersions, uses version 0 for new keys, and sends current versions for conditional puts/deletes;
  • serializes/cache-updates successful mutations and surfaces VssError::ConflictError to the caller;
  • optionally uses global_version where store-wide ordering is required;
  • authenticates the target stored version with the key, then compares the decrypted version with the outer returned version; and
  • documents that CAS/version binding handles honest-server races, while malicious full rollback still needs an external trusted high-water mark?

We can prepare the change and rollback/concurrent-writer tests once we know whether this matches the intended design.


Context: graduated-wallet (Emergent) uses ldk-node via orange-sdk; this came out of our client-side custody audit. Happy to answer questions or provide traces.

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