get_and_store_authenticated_block() stores an authenticated block in two separate steps:
- store the block header with
has_client_notes = true
- store the MMR authentication nodes for that block
In the SQLite store, these are two separate transactions. If the client crashes, or the second write fails, after step 1 but before step 2, the database is left in a bad state.
The block header says the block should be tracked, but the MMR nodes needed to rebuild the PartialMmr are missing.
After that, get_current_partial_mmr() can fail with:
MmrError::InconsistentPartialMmr("tracked leaf at position ... has no value in nodes")
This can leave the client stuck until the database is repaired manually.
Expected behavior: storing an authenticated block should be all-or-nothing. The header and its MMR nodes should either both be stored, or neither should be stored.
Suggested fix: add one store method that stores the block header and the MMR nodes in a single transaction, similar to how apply_state_sync already stores sync updates atomically.
get_and_store_authenticated_block()stores an authenticated block in two separate steps:has_client_notes = trueIn the SQLite store, these are two separate transactions. If the client crashes, or the second write fails, after step 1 but before step 2, the database is left in a bad state.
The block header says the block should be tracked, but the MMR nodes needed to rebuild the
PartialMmrare missing.After that,
get_current_partial_mmr()can fail with:MmrError::InconsistentPartialMmr("tracked leaf at position ... has no value in nodes")This can leave the client stuck until the database is repaired manually.
Expected behavior: storing an authenticated block should be all-or-nothing. The header and its MMR nodes should either both be stored, or neither should be stored.
Suggested fix: add one store method that stores the block header and the MMR nodes in a single transaction, similar to how
apply_state_syncalready stores sync updates atomically.