Skip to content

Commit ae973cb

Browse files
SWvheerdenclaude
andcommitted
refactor: wrap set_as_unmined in a diesel transaction
Wrap the entire set_as_unmined body in conn.transaction() so that the status update, payref archival, and payref deletion all happen atomically. If any step fails, the entire operation rolls back. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 15d7bc6 commit ae973cb

File tree

1 file changed

+45
-41
lines changed
  • base_layer/wallet/src/transaction_service/storage

1 file changed

+45
-41
lines changed

base_layer/wallet/src/transaction_service/storage/sqlite_db.rs

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,20 +2424,23 @@ impl CompletedTransactionSql {
24242424
}
24252425

24262426
pub fn set_as_unmined(tx_id: TxId, conn: &mut SqliteConnection) -> Result<(), TransactionStorageError> {
2427-
// First, get the existing transaction
2428-
let existing_tx = completed_transactions::table
2429-
.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64))
2430-
.first::<CompletedTransactionSql>(conn)?;
2427+
conn.transaction::<_, TransactionStorageError, _>(|conn| {
2428+
// First, get the existing transaction
2429+
let existing_tx = completed_transactions::table
2430+
.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64))
2431+
.first::<CompletedTransactionSql>(conn)?;
24312432

2432-
let (current_status, current_mined_height) = *completed_transactions::table
2433-
.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64))
2434-
.select((completed_transactions::status, completed_transactions::mined_height))
2435-
.load::<(i32, Option<i64>)>(conn)?
2436-
.first()
2437-
.ok_or(TransactionStorageError::DieselError(DieselError::NotFound))?;
2438-
let current_status = LegacyTransactionStatus::try_from(current_status)
2439-
.map_err(|_| TransactionStorageError::UnexpectedResult("Unknown status".to_string()))?;
2440-
diesel::update(completed_transactions::table.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)))
2433+
let (current_status, current_mined_height) = *completed_transactions::table
2434+
.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64))
2435+
.select((completed_transactions::status, completed_transactions::mined_height))
2436+
.load::<(i32, Option<i64>)>(conn)?
2437+
.first()
2438+
.ok_or(TransactionStorageError::DieselError(DieselError::NotFound))?;
2439+
let current_status = LegacyTransactionStatus::try_from(current_status)
2440+
.map_err(|_| TransactionStorageError::UnexpectedResult("Unknown status".to_string()))?;
2441+
diesel::update(
2442+
completed_transactions::table.filter(completed_transactions::tx_id.eq(tx_id.as_u64() as i64)),
2443+
)
24412444
.set(UpdateCompletedTransactionSql {
24422445
status: match current_status {
24432446
LegacyTransactionStatus::OneSidedConfirmed | LegacyTransactionStatus::OneSidedUnconfirmed => {
@@ -2468,36 +2471,37 @@ impl CompletedTransactionSql {
24682471
.execute(conn)
24692472
.num_rows_affected_or_not_found(1)?;
24702473

2471-
// Archive existing payrefs to history before deleting, so that
2472-
// PayRefs from before a reorg can still be looked up.
2473-
let existing_payrefs = PayrefSql::find_all_by_tx_id(tx_id, conn)?;
2474-
for pr in &existing_payrefs {
2475-
PayrefHistorySql::archive_from_payref(pr, conn)?;
2476-
}
2474+
// Archive existing payrefs to history before deleting, so that
2475+
// PayRefs from before a reorg can still be looked up.
2476+
let existing_payrefs = PayrefSql::find_all_by_tx_id(tx_id, conn)?;
2477+
for pr in &existing_payrefs {
2478+
PayrefHistorySql::archive_from_payref(pr, conn)?;
2479+
}
24772480

2478-
let sent = match existing_tx.sent_output_hashes.as_ref() {
2479-
Some(bytes) => bytes_to_fixedhash_vec(bytes),
2480-
_ => vec![],
2481-
};
2482-
for output in sent {
2483-
PayrefSql::delete(output.as_ref(), conn)?;
2484-
}
2485-
let received = match existing_tx.received_output_hashes.as_ref() {
2486-
Some(bytes) => bytes_to_fixedhash_vec(bytes),
2487-
_ => vec![],
2488-
};
2489-
for output in received {
2490-
PayrefSql::delete(output.as_ref(), conn)?;
2491-
}
2492-
let change = match existing_tx.change_output_hashes.as_ref() {
2493-
Some(bytes) => bytes_to_fixedhash_vec(bytes),
2494-
_ => vec![],
2495-
};
2496-
for output in change {
2497-
PayrefSql::delete(output.as_ref(), conn)?;
2498-
}
2481+
let sent = match existing_tx.sent_output_hashes.as_ref() {
2482+
Some(bytes) => bytes_to_fixedhash_vec(bytes),
2483+
_ => vec![],
2484+
};
2485+
for output in sent {
2486+
PayrefSql::delete(output.as_ref(), conn)?;
2487+
}
2488+
let received = match existing_tx.received_output_hashes.as_ref() {
2489+
Some(bytes) => bytes_to_fixedhash_vec(bytes),
2490+
_ => vec![],
2491+
};
2492+
for output in received {
2493+
PayrefSql::delete(output.as_ref(), conn)?;
2494+
}
2495+
let change = match existing_tx.change_output_hashes.as_ref() {
2496+
Some(bytes) => bytes_to_fixedhash_vec(bytes),
2497+
_ => vec![],
2498+
};
2499+
for output in change {
2500+
PayrefSql::delete(output.as_ref(), conn)?;
2501+
}
24992502

2500-
Ok(())
2503+
Ok(())
2504+
})
25012505
}
25022506

25032507
#[allow(dead_code)]

0 commit comments

Comments
 (0)