0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-08 10:31:50 -05:00

sqlite: guard against dangling to-be-reverted db transactions

If the handler that initiated the database transaction is destroyed,
the ongoing transaction cannot be left dangling when the db txn fails
to abort. It must be forcefully reversed; otherwise, any subsequent
db handler executing a write operation will dump the dangling,
to-be-reverted transaction data to disk.

This not only breaks the database isolation property but also results
in the improper storage of incomplete information on disk, impacting
the wallet consistency.
This commit is contained in:
furszy 2024-01-15 20:43:09 -03:00
parent 472d2ca981
commit fc0e747192
No known key found for this signature in database
GPG key ID: 5DD23CCC686AA623

View file

@ -405,12 +405,18 @@ SQLiteBatch::SQLiteBatch(SQLiteDatabase& database)
void SQLiteBatch::Close()
{
bool force_conn_refresh = false;
// If we began a transaction, and it wasn't committed, abort the transaction in progress
if (m_database.HasActiveTxn()) {
if (TxnAbort()) {
LogPrintf("SQLiteBatch: Batch closed unexpectedly without the transaction being explicitly committed or aborted\n");
} else {
LogPrintf("SQLiteBatch: Batch closed and failed to abort transaction\n");
// If transaction cannot be aborted, it means there is a bug or there has been data corruption. Try to recover in this case
// by closing and reopening the database. Closing the database should also ensure that any changes made since the transaction
// was opened will be rolled back and future transactions can succeed without committing old data.
force_conn_refresh = true;
LogPrintf("SQLiteBatch: Batch closed and failed to abort transaction, resetting db connection..\n");
}
}
@ -431,6 +437,17 @@ void SQLiteBatch::Close()
}
*stmt_prepared = nullptr;
}
if (force_conn_refresh) {
m_database.Close();
try {
m_database.Open();
} catch (const std::runtime_error&) {
// If open fails, cleanup this object and rethrow the exception
m_database.Close();
throw;
}
}
}
bool SQLiteBatch::ReadKey(DataStream&& key, DataStream& value)