Implement thread-safe BankAccount with deposit, withdraw, and transfer methods#1463
Implement thread-safe BankAccount with deposit, withdraw, and transfer methods#1463RezaSi merged 10 commits intoRezaSi:mainfrom
Conversation
WalkthroughA new BankAccount implementation in Go is introduced with error-handled deposit, withdrawal, and transfer operations. The implementation includes parameter validation, minimum balance constraints, transaction limits, and thread-safe concurrent access using mutexes with deadlock-avoidant locking for transfers between accounts. Changes
Sequence DiagramsequenceDiagram
participant Client
participant AccountA as BankAccount A
participant AccountB as BankAccount B
Client->>AccountA: Transfer(amount, B)
Note over AccountA: Validate amount > 0
Note over AccountA: Check amount ≤ MaxTransactionAmount
rect rgba(100, 150, 200, 0.5)
Note over AccountA,AccountB: Deadlock-avoidant lock acquisition<br/>(sort by pointer address)
AccountA->>AccountA: Acquire lock (lower address)
AccountA->>AccountB: Acquire lock (higher address)
end
AccountA->>AccountA: Verify sufficient funds<br/>Balance - amount ≥ MinBalance
AccountA->>AccountA: Deduct amount from A
AccountA->>AccountB: Add amount to B
rect rgba(100, 150, 200, 0.5)
Note over AccountA,AccountB: Release locks
AccountA->>AccountA: Release lock
AccountA->>AccountB: Release lock
end
AccountA-->>Client: Return error or nil
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
challenge-7/submissions/PopovMarko/solution-template.go (3)
4-8: Consider avoidingunsafepackage by using account IDs for lock ordering.The pointer-based lock ordering works correctly, but using
unsafemay raise concerns during code audits. Since accounts already have uniqueIDfields, you could compare IDs lexicographically to determine lock order, eliminating the need forunsafe.♻️ Alternative using ID comparison
-import ( - "fmt" - "sync" - "unsafe" -) +import ( + "fmt" + "sync" +)Then in
Transfer:// Lock in canonical order to prevent deadlock first, second := a, target if a.ID > target.ID { first, second = second, first }
10-17: ExportedBalancefield allows unsynchronized reads, potentially causing data races.External code can read
account.Balancedirectly while another goroutine is modifying it viaDeposit,Withdraw, orTransfer, creating a data race. Sincemuis unexported, callers cannot safely acquire the lock before reading.Consider making
Balanceunexported and providing a thread-safe getter method. However, if the challenge tests only use the provided methods (and don't access fields directly), this may be acceptable.♻️ Proposed fix with thread-safe getter
type BankAccount struct { ID string Owner string - Balance float64 - MinBalance float64 + balance float64 + minBalance float64 mu sync.Mutex // For thread safety } + +// GetBalance returns the current balance in a thread-safe manner. +func (a *BankAccount) GetBalance() float64 { + a.mu.Lock() + defer a.mu.Unlock() + return a.balance +}Note: This would require updating all internal references from
BalancetobalanceandMinBalancetominBalance.
41-44: Minor: Remove unnecessary blank line.There's an extraneous blank line inside the
Error()method.🧹 Proposed fix
func (e *InsufficientFundsError) Error() string { - return fmt.Sprintf("Insufficient funds, balance %.2f, min balance %.2f", e.Balance, e.MinBalance) }
Soulution for banking account