Skip to content

mts1715/transactions-parser

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Transactions Parser

A Rust-based transaction processing system that handles deposits, withdrawals, disputes, resolves, and chargebacks with complete accuracy and robust error handling.

Overview

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.

How Cases Are Handled

Transaction Types

The system handles five transaction types:

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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)

Client Validation

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: WrongAccount if client mismatch detected

Balance State Management

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)

How Correctness Is Verified

Type System Guarantees

The application leverages Rust's strong type system for correctness:

  1. Fixed-Point Arithmetic: Uses i64 with 4 decimal places to avoid floating-point errors

    • 10000 represents 1.0000 in the Amount type
    • Custom types (Amount, TxId, AccId) prevent type confusion
  2. Checked Arithmetic: All operations use checked_add, checked_sub to prevent silent overflows

    • Returns Result with proper error types
    • Overflow protection throughout
  3. Result Types: All operations return Result<T, TransactionError>

    • Forces error handling
    • Custom error types for each failure mode
    • No panics in normal execution path
  4. Immutable by Default: State changes only through controlled methods

    • Balance methods ensure invariants maintained
    • Transaction processor tracks all state transitions

Testing Approach

The codebase includes 65 comprehensive unit tests across two modules:

Balance Operations (19 tests)

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)

Transaction Processing (40+ tests)

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

Type Conversion Tests (11 tests)

Tests in types.rs ensure:

  • Fixed-point conversion accuracy (f64 ↔ Amount)
  • Precision handling (4 decimal places)
  • Negative value rejection
  • Overflow detection
  • Roundtrip conversions

Sample Data Testing

The repository includes sample data files for validation:

  1. transactions.csv - Small test case with basic operations:

    • Multiple deposits to different clients
    • Withdrawals with decimal precision
    • Validation of formatting and parsing
  2. 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 test

Run with a specific CSV file:

cargo run transactions.csv
cargo run large_transactions.csv

Test Coverage

The 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)

Architecture

Fixed-Point Arithmetic

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

Error Handling

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),
}

State Management

The TransactionProcessor maintains three collections:

  • clients: HashMap<AccId, Balance> - Account balances
  • transactions: HashMap<TxId, Transaction> - Transaction history
  • disputes: HashSet<TxId> - Active disputes

This structure enables:

  • O(1) lookups for transactions and clients
  • Duplicate dispute prevention
  • Efficient dispute resolution

Usage

# 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 -- --nocapture

Output Format

The 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)

Key Design Decisions

Why Fixed-Point Arithmetic?

Floating-point arithmetic introduces precision errors. Using i64 with 4 decimal places ensures exact decimal calculations, critical for financial applications.

Why Custom Error Types?

Custom error types provide:

  • Type safety (can't confuse error conditions)
  • Clear error messages
  • Proper error propagation
  • No exception-based control flow

Why HashMap Storage?

  • O(1) lookups for clients and transactions
  • Efficient for sparse data
  • Memory-efficient for large datasets
  • Natural duplicate prevention

Performance

  • 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

Memory Usage

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.

Safety Guarantees

  1. No Silent Failures: All operations return Result types
  2. No Panics: Checked arithmetic prevents overflows
  3. Type Safety: Custom types prevent value confusion
  4. State Validation: Client matching enforced for all operations
  5. Invariant Preservation: Balance state always consistent

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages