Migrate db write to atomic - #51
Open
Bastia01 wants to merge 16 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request migrates database write operations to use atomic transactions, significantly improving data consistency and reliability across the application. The changes introduce a new transaction management pattern using GORM's transaction support, along with several important bug fixes and security improvements.
Changes:
- Introduced
WithTransactionhelper andgetExecutorfunction to enable optional transaction support in storage layer functions - Migrated storage write functions to accept
*gorm.DBparameter, allowing them to participate in transactions - Wrapped related database operations in service layer with
WithTransactionto ensure atomicity - Fixed SQL injection vulnerability, array bounds checking issues, signal handling, and various error handling bugs
- Changed
GetOrCreateAccountcalls toGetAccountwith explicit nil checks, preventing unintended account creation
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| storage/tx.go | New file introducing WithTransaction wrapper and getExecutor helper for transaction management |
| storage/userInfoStorer.go | Migrated CreateUserInfo to accept transaction parameter |
| storage/statsStorer.go | Migrated CreateStats to accept transaction parameter |
| storage/preferencesStorer.go | Migrated preference functions to support transactions; added GetPreferenceByAddressForUpdate with SELECT FOR UPDATE locking |
| storage/kycStorer.go | Migrated CreateOrUpdateKyc to accept transaction; improved error handling with errors.Is |
| storage/invoiceStorer.go | Fixed SQL injection vulnerability and error handling bug |
| storage/invoiceDraftStorer.go | Migrated invoice draft functions to accept transaction parameter |
| storage/burnEventStorer.go | Migrated CreateBurnEvent to accept transaction parameter |
| storage/allocationStorer.go | Migrated allocation functions to accept transaction parameter |
| storage/accountStorer.go | Migrated UpdateAccount to accept transaction parameter |
| storage/sellerStorer.go | Added nil check for GetSellerByCode when no rows found |
| service/sumsubService.go | Wrapped KYC updates in transaction; fixed typo in error message |
| service/statsService.go | Wrapped stats generation in transaction for atomicity |
| service/oblioService.go | Enhanced error handling to include warning in email notification |
| service/monthlyPoaiInvoiceService.go | Refactored to use transactions with SELECT FOR UPDATE locking to prevent race conditions in invoice number generation |
| service/emailService.go | Added optional warning parameter to buy license email |
| service/accountService.go | Added GetAccount function; wrapped account/KYC updates in transactions; reordered operations to send email before DB update (introduces potential issue) |
| proxy/handlers/sumsub.go | Changed to use GetAccount instead of GetOrCreateAccount with explicit nil check |
| proxy/handlers/seller.go | Changed to use GetAccount; added nil checks for empty slices |
| proxy/handlers/license.go | Changed to use GetAccount; moved invoice creation after signature generation |
| proxy/handlers/invoiceDraft.go | Updated calls to pass nil for transaction parameter |
| proxy/handlers/burnReport.go | Added bounds checking to prevent index out of range panics |
| proxy/handlers/account.go | Changed multiple handlers to use GetAccount; reordered operations in blacklist handler (introduces potential issue) |
| cmd/main.go | Fixed signal handling to use syscall.SIGTERM instead of deprecated os.Kill |
Comments suppressed due to low confidence (3)
service/accountService.go:20
- Typo in function name: "getAcocunt" should be "getAccount". This function is called in the newly added GetAccount function.
account, err := getAcocunt(address)
service/accountService.go:84
- The order of operations here creates a potential inconsistency. The confirmation email is sent on line 73 before the account is updated on line 81. If the database update fails after the email is sent, the user will receive a confirmation email but the account won't have the pending email recorded, making the confirmation link invalid. Consider moving the database update before sending the email, or wrapping both operations in a transaction with a rollback mechanism for the email.
err = SendConfirmEmail(address, email)
if err != nil {
return nil, errors.New("error while sending confirmation email: " + err.Error())
}
account.PendingEmail = email
account.PendingReceiveUpdates = receiveUpdates
err = storage.UpdateAccount(nil, account)
if err != nil {
return nil, errors.New("error while updating account on storage: " + err.Error())
}
proxy/handlers/account.go:458
- The order of operations creates a potential inconsistency. The blacklist email is sent on line 424 before the account is updated on line 453. If the database update fails after the email is sent, the user will receive a blacklist notification but the account won't actually be blacklisted in the database. Consider moving the database update before sending the email, or wrapping both operations in a transaction-like pattern.
err = service.SendBlacklistedEmail(*account.Email)
if err != nil {
log.Error("error while sending blacklisted email: " + err.Error())
model.JsonResponse(c, http.StatusBadRequest, nil, nodeAddress, err.Error())
return
}
kyc, _, err := storage.GetKycByEmail(*account.Email)
if err != nil {
log.Error("error while retrieving kyc information from storage: " + err.Error())
model.JsonResponse(c, http.StatusInternalServerError, nil, nodeAddress, err.Error())
return
}
accountDto, err = service.NewAccountDto(account, kyc)
if err != nil {
log.Error("error while creating account dto: " + err.Error())
model.JsonResponse(c, http.StatusInternalServerError, nil, nodeAddress, err.Error())
return
}
} else {
accountDto, err = service.NewAccountDto(account, nil)
if err != nil {
log.Error("error while creating account dto: " + err.Error())
model.JsonResponse(c, http.StatusInternalServerError, nil, nodeAddress, err.Error())
return
}
}
err = storage.UpdateAccount(nil, account)
if err != nil {
log.Error("error while updating account: " + err.Error())
model.JsonResponse(c, http.StatusInternalServerError, nil, nodeAddress, err.Error())
return
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Bastia01
force-pushed
the
migrate-db-write-to-atomic
branch
from
February 20, 2026 16:44
fcf869f to
c65a997
Compare
…mpty invoice would have been created anyway
… not happen again)
…rned, creating issue in the next part of the enable/disable seller code endpoint ( saving empty data)
…ured between backend <-> DB, previous and empty error would have been returned
aledefra
force-pushed
the
migrate-db-write-to-atomic
branch
from
June 10, 2026 13:40
c65a997 to
e029bbc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.