Skip to content

TxGraph:: apply_changeset ignores ChangeSet::first_seen #2270

Description

@CapThunder19

Describe the bug

TxGraph::apply_changeset loops over txs, txouts, anchors, last_seen and last_evicted but not first_seen. Meanwhile initial_changeset() does write first_seen out, so persist and apply don't match up.

the value doesn't just come back as None apply_changeset still replays last_seen via insert_seen_at, which calls update_first_seen internally, and on an empty graph that entry is vacant so it just takes the last_seen value So after a reload every tx ends up with first_seen == last_seen.

SQLite isn't the problem the changeset that comes back off disk has the right values. They get thrown away when it's applied to the graph.

first_seen is the primary sort key for unconfirmed txs in ChainPosition::Ord Once it equals last_seen the ordering can change across a restart, without anything else changing.

To Reproduce

Two unconfirmed txs where first_seen and last_seen disagree on order, through a real sqlite file (write, close, reopen, apply):

before:  A = (100, 500)   B = (200, 300)   order = [A, B]

changeset off disk:  first_seen = {A: 100, B: 200}   <- fine
                     last_seen  = {A: 500, B: 300}

after apply_changeset:  A = (500, 500)   B = (300, 300)   order = [B, A]

Also reproduces with no database at all:

let mut reloaded = TxGraph::<BlockId>::default();
reloaded.apply_changeset(graph.initial_changeset());
// first_seen is now last_seen

Expected behavior

initial_changeset() to apply_changeset() should round-trip, and unconfirmed ordering shouldn't change just because you restarted.

Build environment

  • BDK tag/commit: 337e9d68, bdk_chain 0.23.2 (apply_changeset is the same on master)
  • OS+version: Windows 11
  • Rust/Cargo version: 1.97.1
  • Rust/Cargo target: x86_64-pc-windows-msvc

Which backend(s) are relevant (if any)?

  • Electrum
  • Esplora
  • Bitcoin Core RPC
  • None / not backend-related (e.g. bdk_chain, bdk_core)
  • Other (please specify): ____

Is this blocking production use?

  • Yes
  • No

Additional context

first_seen was added in #1947/#1950 and persisted in #1965/#1966, so it's computed and stored on purpose it just never gets read back. #1966's test checks the reloaded changeset has first_seen but never applies it to a graph, which is why this slipped through

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

    bugSomething isn't working

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions