Skip to content

fix(chain): restore first seen timestamps in TxGraph - #2346

Open
NaitikVerma6776 wants to merge 2 commits into
bitcoindevkit:masterfrom
NaitikVerma6776:fix/2270-restore-first-seen
Open

NaitikVerma6776 wants to merge 2 commits into
bitcoindevkit:masterfrom
NaitikVerma6776:fix/2270-restore-first-seen

Conversation

@NaitikVerma6776

@NaitikVerma6776 NaitikVerma6776 commented Oct 6, 2026 •

Copy link
Copy Markdown

Fixes #2270.

TxGraph::apply_changeset was restoring last_seen but not first_seen. Replaying last_seen through insert_seen_at could therefore incorrectly set first_seen to the last_seen timestamp.

This change restores first_seen and last_seen independently when applying a ChangeSet.

A regression test was added to verify that distinct first_seen and last_seen timestamps survive applying and reloading a changeset.

Tests

  • cargo +nightly fmt --all -- --check — passed
  • git diff --check — passed
  • Full Rust test suite could not be run locally because the Windows environment does not have the MSVC link.exe linker installed.

Contribution checklist

  • Regression test added
  • Changes are limited to the relevant chain implementation and test
  • Commit is GPG signed

@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.

Please also sign your commits.

Comment thread crates/chain/src/tx_graph.rs Outdated
Comment on lines 987 to 994
// Restore first_seen and last_seen independently. Replaying last_seen via
// `insert_seen_at` on an empty graph would set first_seen to last_seen.
for (txid, seen_at) in changeset.first_seen {
let _ = self.update_first_seen(txid, seen_at);
}
for (txid, seen_at) in changeset.last_seen {
let _ = self.insert_seen_at(txid, seen_at);
let _ = self.update_last_seen(txid, seen_at);
}

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.

Suggested change
// Restore first_seen and last_seen independently. Replaying last_seen via
// `insert_seen_at` on an empty graph would set first_seen to last_seen.
for (txid, seen_at) in changeset.first_seen {
let _ = self.update_first_seen(txid, seen_at);
}
for (txid, seen_at) in changeset.last_seen {
let _ = self.insert_seen_at(txid, seen_at);
let _ = self.update_last_seen(txid, seen_at);
}
// Restore first_seen and last_seen independently. Replaying last_seen via
// `insert_seen_at` on an empty graph would set first_seen to last_seen.
for (txid, seen_at) in changeset.first_seen {
let _ = self.insert_seen_at(txid, seen_at);
}
for (txid, seen_at) in changeset.last_seen {
let _ = self.insert_seen_at(txid, seen_at);
}

It's safer to call insert_seen_at for both changeset fields to avoid the last_seen >= first_seen contract from being violated.

@NaitikVerma6776

NaitikVerma6776 commented Oct 6, 2026 •

Copy link
Copy Markdown
Author

@evanlinjin Please review the changes
happy to receive feedback

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

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

TxGraph:: apply_changeset ignores ChangeSet::first_seen

2 participants