A Rust-based transaction processing system that handles deposits, withdrawals, disputes, resolves, and chargebacks with complete accuracy and robust error handling.
This application processes financial transactions from CSV files, maintaining accurate account balances with support for dispute resolution workflows. It uses fixed-point arithmetic to ensure decimal precision (4 decimal places) and comprehensive error handling to maintain data integrity.
The system handles five transaction types:
-
Deposit - Adds funds to a client account
- Creates account if it doesn't exist
- Validates amount (must be positive)
- Uses checked arithmetic to prevent overflows
-
Withdrawal - Removes funds from a client account
- Requires account to exist
- Validates sufficient available funds (total - locked)
- Blocks withdrawals from frozen accounts
- Prevents withdrawals that would make locked funds unavailable
-
Dispute - Temporarily locks funds pending investigation
- Requires transaction to exist and not already disputed
- Validates that dispute is initiated by the transaction's original client
- Locks the transaction amount in the account
- Prevents duplicate disputes
-
Resolve - Releases disputed funds back to available balance
- Requires active dispute
- Validates that resolve is initiated by the transaction's original client
- Reduces locked amount
- Account remains unfrozen
-
Chargeback - Permanently removes disputed funds and freezes account
- Requires active dispute
- Validates that chargeback is initiated by the transaction's original client
- Removes funds from both total and locked amounts
- Freezes the account (prevents future withdrawals)
The system enforces strict client validation for dispute/resolve/chargeback operations:
- Each operation checks that the transaction's original client matches the operation's client
- Prevents unauthorized dispute operations by different clients
- Error:
WrongAccountif client mismatch detected
Each account maintains three key attributes:
- total: Available balance (reduced by withdrawals, freezes on chargeback)
- locked: Disputed funds temporarily unavailable
- frozen: Boolean flag indicating account is frozen (blocks withdrawals and new transactions)
The application leverages Rust's strong type system for correctness:
-
Fixed-Point Arithmetic: Uses
i64with 4 decimal places to avoid floating-point errors10000represents1.0000in the Amount type- Custom types (
Amount,TxId,AccId) prevent type confusion
-
Checked Arithmetic: All operations use
checked_add,checked_subto prevent silent overflows- Returns
Resultwith proper error types - Overflow protection throughout
- Returns
-
Result Types: All operations return
Result<T, TransactionError>- Forces error handling
- Custom error types for each failure mode
- No panics in normal execution path
-
Immutable by Default: State changes only through controlled methods
Balancemethods ensure invariants maintained- Transaction processor tracks all state transitions
The codebase includes 65 comprehensive unit tests across two modules:
Tests in parser.rs cover:
- Basic operations (deposit, withdrawal, dispute, resolve, chargeback)
- Edge cases (zero amounts, exact balances, overflows)
- Error conditions (insufficient funds, frozen accounts, underflow)
- State transitions (total, locked, frozen flags)
Tests verify:
- Deposit operations (new/existing clients, overflow protection)
- Withdrawal operations (client validation, fund availability, frozen account handling)
- Dispute workflow (transaction existence, client matching, duplicate prevention)
- Resolve workflow (dispute existence, client matching)
- Chargeback workflow (dispute existence, account freezing, fund removal)
- Error conditions for each transaction type
- Integration scenarios with multiple clients
Tests in types.rs ensure:
- Fixed-point conversion accuracy (f64 ↔ Amount)
- Precision handling (4 decimal places)
- Negative value rejection
- Overflow detection
- Roundtrip conversions
The repository includes sample data files for validation:
-
transactions.csv- Small test case with basic operations:- Multiple deposits to different clients
- Withdrawals with decimal precision
- Validation of formatting and parsing
-
large_transactions.csv- Large-scale test (9,799 transactions):- Performance testing
- Memory efficiency validation
- Edge cases in large datasets
- Multiple clients with complex transaction histories
Run the tests with:
cargo testRun with a specific CSV file:
cargo run transactions.csv
cargo run large_transactions.csvThe 65 tests ensure:
- ✅ All transaction types work correctly
- ✅ Error conditions are properly handled
- ✅ Overflow/underflow protection
- ✅ Client matching validation
- ✅ Account state transitions
- ✅ Frozen account behavior
- ✅ Insufficient funds handling
- ✅ Duplicate dispute prevention
- ✅ Decimal precision (4 places)
All monetary amounts use fixed-point arithmetic with 4 decimal places to avoid floating-point precision errors:
pub type Amount = i64; // 1.0000 = 10000
pub const DECIMAL_PLACES: u8 = 4;Benefits:
- No rounding errors (exact decimal arithmetic)
- Deterministic calculations
- Safe comparisons (no epsilon checks needed)
- Overflow detection via checked arithmetic
Custom error types provide clear error messages:
pub enum TransactionError {
(),
NotEnoughFunds(String),
TransactionNotFound(u32),
DisputeNotFound(u32),
TransactionAlreadyDisputed(),
WrongAccount(String),
Overflow(String),
InvalidAmount(String),
IoError(String),
CsvParseError(String),
}The TransactionProcessor maintains three collections:
clients: HashMap<AccId, Balance>- Account balancestransactions: HashMap<TxId, Transaction>- Transaction historydisputes: HashSet<TxId>- Active disputes
This structure enables:
- O(1) lookups for transactions and clients
- Duplicate dispute prevention
- Efficient dispute resolution
# Build the project
cargo build --release
# Run with default file (transactions.csv)
cargo run
# Run with custom file
cargo run large_transactions.csv
# Run tests
cargo test
# Run tests with output
cargo test -- --nocaptureThe program outputs CSV with sorted client IDs:
client, available, held, total, locked
1, 1.0, 0, 1.0, false
2, 0, 2.0, 2.0, false
Columns:
- client: Client ID
- available: Available balance (not locked in disputes)
- held: Funds locked in active disputes
- total: Total balance (available + held)
- locked: Whether account is frozen (true/false)
Floating-point arithmetic introduces precision errors. Using i64 with 4 decimal places ensures exact decimal calculations, critical for financial applications.
Custom error types provide:
- Type safety (can't confuse error conditions)
- Clear error messages
- Proper error propagation
- No exception-based control flow
- O(1) lookups for clients and transactions
- Efficient for sparse data
- Memory-efficient for large datasets
- Natural duplicate prevention
- Processes 9,799 transactions in milliseconds
- Constant-time lookups for clients and transactions (O(1))
- Streaming CSV parsing (line-by-line)
- Output sorted by client ID for readability
Maximum RAM usage can reach tens of gigabytes since all transactions from CSV are stored in memory using HashMap data structures. The number of unique clients has minimal impact - even with all possible account IDs (65,536 max from u16), this is only a few megabytes.
Memory breakdown per transaction:
- Transaction key (TxId/u32): 4 bytes
- Transaction value: 16 bytes (client: u16, amount: i64)
- HashMap overhead: ~14 bytes (0.73 load factor average)
- Total per transaction: ~33 bytes
Practical memory estimates:
- 100K transactions: ~3.4 MB
- 1M transactions: ~34 MB
- 100M transactions: ~3.4 GB
- 1B transactions: ~34 GB
Note: Client accounts (HashMap<AccId, Balance>) contribute much less since the maximum number of unique clients is limited to 65,536 (u16 max), consuming only a few megabytes total.
- No Silent Failures: All operations return
Resulttypes - No Panics: Checked arithmetic prevents overflows
- Type Safety: Custom types prevent value confusion
- State Validation: Client matching enforced for all operations
- Invariant Preservation: Balance state always consistent