Skip to content

Replace bincode by postcard - #2258

Open
nymius wants to merge 1 commit into
bitcoindevkit:masterfrom
nymius:push-ronzxprlmnpx
Open

Replace bincode by postcard#2258
nymius wants to merge 1 commit into
bitcoindevkit:masterfrom
nymius:push-ronzxprlmnpx

Conversation

@nymius

@nymius nymius commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

bincode is no longer maintained.
postcard is the closest maintained project with >52M downloads on crates.io, regular releases, and activity on its repo.

BREAKING CHANGE:

  • Magic Bytes should be changed to avoid accidentaly modifying old file store blobs.
  • The internal encoding has changed as a result of using postcard. Old file stores won't be recoverable using the latest file_store version.
  • As this is a development environment store, we don't provide migration utilities.
  • StoreError::Bincode has been renamed to StoreError::Decode, and now contains postcard::Errors
  • From now on, trailing bytes after decoding are rejected.
  • append always tries to attach changesets to the latest valid end of the file.

These changes were LLM assisted.

Changelog notice

Changed

  • Replaced bincode (unmaintained) with postcard for on-disk (de)serialization.
    • BREAKING CHANGE: the on-disk format has changed. Existing store files are not readable by this
      version; callers should bump their magic bytes so old files fail fast with
      StoreError::InvalidMagicBytes instead of a decode error.
    • BREAKING CHANGE: StoreError::Bincode(bincode::ErrorKind) is replaced by
      StoreError::Decode(postcard::Error).
  • BREAKING CHANGE: Entry length prefix changed from an 8-byte little-endian integer to a
    postcard varint (1-10 bytes). Covered by the same on-disk format change and
    magic-byte-bump guidance above.

Fixed

  • Store::append now seeks to the end of the file before writing, so appending through a
    stale handle no longer overwrites changesets written via another handle. A failed append
    also truncates the partial frame, leaving the file unchanged.
  • Entries whose payload doesn't consume its whole declared frame length are now rejected instead of ignored.

Checklists

All Submissions:

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

@nymius nymius changed the title refactor(file_store)!: replace bincode by postcard Replace bincode by postcard Aug 13, 2026
@luisschwab luisschwab moved this to Needs Review in BDK Chain Aug 13, 2026
@nymius
nymius force-pushed the push-ronzxprlmnpx branch from 4ba69d3 to 007c1d2 Compare August 14, 2026 12:49
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.80952% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 78.67%. Comparing base (5108b5c) to head (1bde283).

Files with missing lines Patch % Lines
crates/file_store/src/lib.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2258      +/-   ##
==========================================
+ Coverage   78.36%   78.67%   +0.30%     
==========================================
  Files          30       30              
  Lines        5945     6002      +57     
  Branches      281      286       +5     
==========================================
+ Hits         4659     4722      +63     
+ Misses       1210     1206       -4     
+ Partials       76       74       -2     
Flag Coverage Δ
rust 78.67% <98.80%> (+0.30%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nymius
nymius force-pushed the push-ronzxprlmnpx branch 2 times, most recently from 82c6cae to 28a4592 Compare August 14, 2026 15:18
`bincode` is no longer maintained.
`postcard` is the closest maintained project with >52M downloads on
crates.io, regular releases, and activity on its repo.

BREAKING CHANGE:
- Magic Bytes should be changed to avoid accidentaly modifying old file
  store blobs.
- The internal encoding has changed as a result of using postcard. Old
  file stores won't be recoverable using the latest file_store version.
- As this is a development environment store, we don't provide migration
  utilities.
- `StoreError::Bincode` has been renamed to `StoreError::Decode`, and
  now contains `postcard::Error`s
- From now on, trailing bytes after decoding are rejected.
- `append` always tries to attach changesets to the latest valid end of
  the file.
@nymius
nymius force-pushed the push-ronzxprlmnpx branch from 28a4592 to 1bde283 Compare August 14, 2026 16:13
@chukwudiikeh

Copy link
Copy Markdown

Breaking compatibility with older bincode-encoded stores without supplying a conversion tool leaves users stranded. Regardless of whether file_store is intended for dev environments, dropping support without providing a migration path or prior notice inevitably leads to silent data loss.

@evanlinjin

Copy link
Copy Markdown
Member

@chukwudiikeh There is no data loss. Everything to persist in bdk_chain is blockchain data, which is always available in the blockchain.

@evanlinjin evanlinjin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't reviewed the tests yet.

EntryIter changes are well written and very thorough - handling all situations elegantly and returning useful errors.

I disagree with the Store::append changes as a corrupted tail becomes unrecoverable.

Comment on lines +123 to +129
let mut payload = Vec::new();
// Reserve exactly `len` bytes up front. Fail fast on a corrupt, oversized length prefix.
// Avoids unnecessary reads and allocations.
let alloc_failed = usize::try_from(len)
.map_err(|_| ())
.and_then(|len| payload.try_reserve_exact(len).map_err(|_| ()))
.is_err();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there no better way to write this? 😅

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use postcard::from_io instead?

Comment on lines +256 to +258
// Always write at the current end of the file. This handle's cursor may be stale if
// another handle has appended since we last read, and writing at a stale offset would
// overwrite those changesets.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the behavior we want. If we failed to read the last entry due to DeserializeUnexpectedRead, then further writes will also be corrupted and unreadable due to the len_prefixes being unaligned.

@evanlinjin

Copy link
Copy Markdown
Member

Entry length prefix changed from an 8-byte little-endian integer to a
postcard varint (1-10 bytes). Covered by the same on-disk format change and
magic-byte-bump guidance above.

The version on master used varint length prefixes as well.

@luisschwab

Copy link
Copy Markdown
Member

Breaking compatibility with older bincode-encoded stores without supplying a conversion tool leaves users stranded. Regardless of whether file_store is intended for dev environments, dropping support without providing a migration path or prior notice inevitably leads to silent data loss.

This crate is explicitly for testing only, per the README.

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

Labels

None yet

Projects

Status: Needs Review

Development

Successfully merging this pull request may close these issues.

4 participants