> For the complete documentation index, see [llms.txt](https://docs.xrpl-commons.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xrpl-commons.org/core-dev-bootcamp/module07/homeworks/homework1.md).

# Homework 1: Building a Custom RPC Handler

[← Back to Building and Integrating Custom RPC Handlers](/core-dev-bootcamp/module07.md)

***

### Overview

In this comprehensive workshop, you will implement a **complete RPC handler** from scratch. This exercise will consolidate everything you've learned by having you build a production-quality `GetAccountBalance` command for Rippled.

**Estimated Time**: 4-6 hours

**Difficulty Level**: Intermediate to Advanced

***

### Learning Objectives

By completing this workshop, you will:

* Understand how handlers are registered in the central handler table
* Implement proper input validation and error handling
* Access ledger data through the JsonContext API
* Calculate XRP reserves and available balances
* Build well-structured JSON responses
* Write comprehensive unit tests for your handler
* Follow Rippled coding conventions and best practices

***

### Prerequisites

Before starting this workshop, ensure you have:

* [ ] Completed Rippled compilation and setup
* [ ] Completed Understanding Rippled architecture
* [ ] Read all RPC Handler Architecture through Best Practices
* [ ] Working Rippled development environment with build tools
* [ ] Familiarity with C++20 features
* [ ] Google Test framework installed and configured

***

### The Challenge

You will implement a new RPC command called `get_account_balance` that provides detailed balance information for an XRP Ledger account, including:

* **Current XRP balance**
* **Base reserve requirement**
* **Owner reserve requirement** (based on owned objects)
* **Available balance** (balance minus reserves)
* **Owner count** (number of owned ledger objects)
* **Optional**: Trust line balances (if requested)

***

### Part 1: Understanding the RPC System

Before writing code, answer these architectural questions to demonstrate your understanding:

#### Questions

1. **Handler Discovery**
   * How does Rippled locate and invoke the correct handler when a request arrives?
   * What data structure stores the mapping between command names and handler functions?
   * Where in the codebase is this mapping defined?
2. **Request Lifecycle**
   * Trace the complete journey of an RPC request from reception to response
   * What stages does a request pass through?
   * At what point is permission checking performed?
3. **Role-Based Access Control**
   * What are the five role levels in Rippled's RBAC system?
   * How is a client's role determined?
   * Can you explain the difference between GUEST, USER, and ADMIN roles?

**Write your answers** in [answers.md](https://github.com/XRPL-Commons/xrpl-trainings/blob/main/core-dev-bootcamp/module07/homeworks/answers.md)

***

### Part 2: Handler Implementation

#### Task 2.1: Create the Handler File

Create a new file:

**File**: `src/xrpld/rpc/handlers/GetAccountBalance.cpp\`

Follow the standard file header format used in other handlers.

#### Task 2.2: Implement the Handler Function

Your handler must:

1. **Validate the `account` parameter**
   * Check if the field exists
   * Validate the account address format
   * Return appropriate errors for invalid input
2. **Handle optional `ledger_index` parameter**
   * Support `"current"`, `"validated"`, `"closed"`
   * Support specific ledger numbers
   * Default to current ledger if not specified
3. **Query the ledger for account data**
   * Use `RPC::lookupLedger()` to get the ledger
   * Read the account object using `keylet::account()`
   * Handle account not found scenario
4. **Calculate balance information**
   * Get current XRP balance
   * Calculate base reserve (from fees)
   * Calculate owner reserve (based on owner count)
   * Compute available balance (balance - total reserve)
5. **Build the response**
   * Include all required fields
   * Use proper JSON structure
   * Mark response as validated when appropriate

#### Task 2.3: Register the Handler

Add your handler to the central handler table:

**File**: `src/xrpld/rpc/handlers/Handlers.cpp`

Choose appropriate values for:

* Minimum required role
* Execution conditions
* API version support

#### Task 2.4: Expected Request Format

```json
{
    "method": "get_account_balance",
    "params": [{
        "account": "rN7n7otQDd6FczFgLdlqtyMVrn3NnrcVXs",
        "ledger_index": "validated"
    }]
}
```

#### Task 2.5: Expected Response Format

```json
{
    "result": {
        "account": "rN7n7otQDd6FczFgLdlqtyMVrn3NnrcVXs",
        "balance": "1000000000",
        "available_balance": "990000000",
        "base_reserve": "10000000",
        "owner_reserve": "0",
        "total_reserve": "10000000",
        "owner_count": 0,
        "ledger_index": 12345,
        "validated": true
    }
}
```

***

### Part 3: Error Handling

Your handler must properly handle these error scenarios:

#### Required Error Cases

1. **Missing `account` field**
   * Error: `rpcINVALID_PARAMS`
   * Message: "Missing 'account' field"
2. **Invalid account format**
   * Error: `rpcACT_MALFORMED`
   * Message: "Invalid account address"
3. **Account not found**
   * Error: `rpcACT_NOT_FOUND`
   * Message: "Account not found"
4. **Ledger not available**
   * Error: `rpcLGR_NOT_FOUND`
   * Message: "Ledger not found"
5. **Invalid ledger index**
   * Error: `rpcINVALID_PARAMS`
   * Message: "Invalid ledger\_index"

#### Task 3.1: Implement Error Handling

Ensure each error case returns the proper error code and a descriptive message.

***

### Part 4: Input Validation

Implement comprehensive validation for:

#### Task 4.1: Account Parameter

```cpp
// Validate account exists
if (!context.params.isMember(jss::account)) {
    // Return error
}

// Validate account is a string
if (!context.params[jss::account].isString()) {
    // Return error
}

// Parse and validate account address
auto const account = parseBase58<AccountID>(...);
if (!account) {
    // Return error
}
```

#### Task 4.2: Ledger Parameter

```cpp
// Handle optional ledger_index
if (context.params.isMember(jss::ledger_index)) {
    // Validate format (string or number)
    // Handle special values ("current", "validated", "closed")
    // Validate numeric ranges
}
```

#### Task 4.3: Edge Cases

Handle these special scenarios:

* Empty account string
* Account with no owner count field (shouldn't happen, but be defensive)
* Ledger with missing fee information
* Balance exceeding maximum XRP supply

***

### Part 5: Testing

Create comprehensive unit tests for your handler.

#### Task 5.1: Create Test File

**File**: `src/test/rpc/GetAccountBalance_test.cpp`

#### Task 5.2: Implement Test Cases

**Test 5.2.1: Valid Request**

```cpp
TEST_F(GetAccountBalance_test, validRequest)
{
    // Create account with known balance
    // Call handler with valid parameters
    // Verify response contains correct values
    // Verify all required fields present
}
```

**Test 5.2.2: Invalid Account Address**

```cpp
TEST_F(GetAccountBalance_test, invalidAccount)
{
    // Call handler with malformed account
    // Verify rpcACT_MALFORMED error returned
    // Verify error message is descriptive
}
```

**Test 5.2.3: Account Not Found**

```cpp
TEST_F(GetAccountBalance_test, accountNotFound)
{
    // Call handler with non-existent account
    // Verify rpcACT_NOT_FOUND error returned
}
```

**Test 5.2.4: Ledger Selection**

```cpp
TEST_F(GetAccountBalance_test, ledgerSelection)
{
    // Test with ledger_index = "current"
    // Test with ledger_index = "validated"
    // Test with specific ledger number
    // Verify correct ledger is queried
}
```

**Test 5.2.5: Permission Levels**

```cpp
TEST_F(GetAccountBalance_test, permissions)
{
    // Test with GUEST role
    // Test with USER role
    // Test with ADMIN role
    // Verify appropriate access granted
}
```

**Test 5.2.6: Missing Parameters**

```cpp
TEST_F(GetAccountBalance_test, missingAccount)
{
    // Call handler without account parameter
    // Verify rpcINVALID_PARAMS error returned
}
```

**Test 5.2.7: Reserve Calculations**

```cpp
TEST_F(GetAccountBalance_test, reserveCalculation)
{
    // Create account with owner count = 5
    // Verify base_reserve is correct
    // Verify owner_reserve = base_reserve * owner_count
    // Verify available_balance = balance - total_reserve
}
```

#### Task 5.3: Optional Advanced Tests

* **Concurrent access**: Test handler with multiple simultaneous requests
* **Performance**: Measure handler execution time
* **Ledger transitions**: Test behavior during ledger close
* **Large owner counts**: Test with accounts owning many objects

***

### Part 6: Optional Enhancements

After completing the core implementation, consider these enhancements:

#### Enhancement 6.1: Trust Line Balances

Add optional `include_lines` parameter:

```json
{
    "method": "get_account_balance",
    "params": [{
        "account": "rN7n7otQDd6FczFgLdlqtyMVrn3NnrcVXs",
        "include_lines": true
    }]
}
```

Response includes trust lines:

```json
{
    "result": {
        ...
        "lines": [
            {
                "currency": "USD",
                "issuer": "rN7n7otQDd6FczFgLdlqtyMVrn3NnrcVXs",
                "balance": "100.00"
            }
        ]
    }
}
```

#### Enhancement 6.2: Currency Filtering

Add `currency` filter for trust lines:

```json
{
    "include_lines": true,
    "currency": "USD"
}
```

#### Enhancement 6.3: Pagination

For accounts with many trust lines, add pagination:

```json
{
    "include_lines": true,
    "limit": 50,
    "marker": "..."
}
```

***

### Reference Implementation Files

Study these existing handlers as reference:

1. **AccountInfo.cpp**
   * Location: `src/xrpld/rpc/handlers/AccountInfo.cpp`
   * Similar structure to your handler
   * Shows account querying and response building
2. **AccountLines.cpp**
   * Location: `src/xrpld/rpc/handlers/AccountLines.cpp`
   * Trust line iteration and filtering
   * Pagination implementation
3. **LedgerData.cpp**
   * Location: `src/xrpld/rpc/handlers/LedgerData.cpp`
   * Ledger object iteration
   * Large result set handling
4. **RPCHelpers.h**
   * Location: `src/xrpld/rpc/detail/RPCHelpers.h`
   * Utility functions for common tasks
   * Account parsing, ledger lookup, etc.

***

### Submission Checklist

Before considering your implementation complete:

* [ ] Handler function implemented with proper signature
* [ ] Handler registered in Handlers.cpp
* [ ] All required parameters validated
* [ ] All error cases handled with appropriate codes
* [ ] Response format matches specification
* [ ] Reserve calculations are correct
* [ ] At least 7 unit tests implemented
* [ ] All tests pass
* [ ] Code follows Rippled style guidelines
* [ ] Code compiles without warnings
* [ ] Documentation comments added
* [ ] Edge cases considered and handled

***

### Evaluation Criteria

Your implementation will be evaluated on:

| Criterion          | Weight | Details                                |
| ------------------ | ------ | -------------------------------------- |
| **Correctness**    | 40%    | Handler produces correct results       |
| **Error Handling** | 20%    | All error cases properly handled       |
| **Code Quality**   | 20%    | Follows best practices and conventions |
| **Testing**        | 15%    | Comprehensive test coverage            |
| **Documentation**  | 5%     | Clear comments and documentation       |

***

### Getting Help

If you encounter difficulties:

1. **Review the module topics**
   * Re-read relevant sections
   * Study code examples carefully
2. **Examine existing handlers**
   * AccountInfo.cpp is the best reference
   * Look for similar patterns
3. **Check Rippled documentation**
   * [XRPL RPC Reference](https://xrpl.org/public-api-methods.html)
   * [Rippled Source Code](https://github.com/XRPLF/rippled)
4. **Ask for help**
   * [Contact us via feedback form](https://docs.google.com/forms/d/e/1FAIpQLSe7qIbqepUKGVJxmWFHv0rs1zsBAzk8G6y5-bfz0Yd5rqW_5A/viewform)
   * Share specific error messages or issues

***

### Solution Resources

After attempting the workshop independently:

* **Hints**: For guidance [see hints →](/core-dev-bootcamp/module07/homeworks/hints.md)
* **Code snippets**: For common patterns [see snippets →](/core-dev-bootcamp/module07/homeworks/snippets.md)
* **Full solution**: Available upon request after submission

***

### What You'll Build

By the end of this workshop, you'll have:

* A fully functional RPC handler integrated into Rippled
* Comprehensive error handling and input validation
* Production-quality unit tests
* Understanding of the complete RPC development lifecycle
* Skills to build any custom handler you need

**Good luck! Enjoy building your first RPC handler!**
