Skip to content

fix(consensus-db): tolerate a missing data table during migration - #392

Open
Dusk1e wants to merge 1 commit into
circlefin:mainfrom
Dusk1e:fix/consensus-db-migration-missing-table
Open

fix(consensus-db): tolerate a missing data table during migration#392
Dusk1e wants to merge 1 commit into
circlefin:mainfrom
Dusk1e:fix/consensus-db-migration-missing-table

Conversation

@Dusk1e

@Dusk1e Dusk1e commented Sep 12, 2026

Copy link
Copy Markdown

migrate_certificates and migrate_decided_blocks open their table inside a read transaction:

let mut next_height = if let Some((min_height, _)) = self
    .db
    .begin_read()?
    .open_table(CERTIFICATES_TABLE)?
    .first()?

open_table on a read transaction returns TableDoesNotExist when the table isn't there. The other two table migrations, migrate_undecided_blocks and migrate_pending_parts, open theirs inside a write transaction, which creates it, so those already treat a missing table as an empty one. The first two abort the whole migration instead.

A datadir can reach the migration before the tables exist. Db::new migrates, and only afterwards does Store::open call create_tables. needs_migration records "file exists, no schema version" as v0 and asks for a migration, and redb::Database::create makes the file before that version is ever written — so a first start interrupted between the two leaves a database that every later start rejects with:

Table(TableDoesNotExist("certificates"))

db migrate fails the same way, --dry-run included, since preview_migrate runs the same functions.

The change treats a missing table as empty in both, which is what the other two already do. The added test fails on main with TableDoesNotExist("certificates") and passes with the change; the rest of the crate's suite (107 tests) still passes.

migrate_certificates and migrate_decided_blocks open their table inside a read
transaction, which fails with TableDoesNotExist when the table is not there.
migrate_undecided_blocks and migrate_pending_parts open theirs inside a write
transaction, which creates it, so those two already treat a missing table as an
empty one.

A datadir can reach the migration before the tables exist. Db::new migrates, and
only afterwards does Store::open call create_tables; needs_migration records
"file exists, no schema version" as v0 and asks for a migration, and redb makes
the file before that version is written. A first start interrupted in between
leaves a database that every later start rejects, and `db migrate` rejects it
the same way, dry run included.

Treat a missing table as empty in both, matching the other two.
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.

1 participant