|
1 | 1 | # Repository Guidelines |
2 | 2 |
|
3 | | -This guide helps contributors deliver changes to `buildernet-orderflow-proxy` safely and predictably. |
| 3 | +This guide helps contributors deliver changes to `buildernet-orderflow-proxy-v2` safely and predictably. |
4 | 4 |
|
5 | 5 | ## Project Structure & Module Organization |
| 6 | + |
| 7 | +### Entry Points & Core Structure |
6 | 8 | - The entrypoint binary lives in `src/main.rs` and delegates to the library crate in `src/lib.rs`. |
7 | | -- Domain modules are located under `src/`: |
8 | | - - `ingress/`: Handles HTTP+JSON-RPC requests. |
9 | | - - `priority/`: Scores queues. |
10 | | - - `forwarder.rs`: Relays bundles. |
11 | | - - `rate_limit.rs`: Implements throttling logic. |
12 | | -- Shared helpers are in `types.rs` and `utils.rs`. |
13 | | -- Integration tests are under `tests/`, with reusable fixtures in `tests/common/`. |
| 9 | +- CLI arguments are defined in `src/cli.rs` using the `clap` crate. |
| 10 | +- The `src/runner/` module handles application lifecycle and HTTP server setup. |
| 11 | + |
| 12 | +### Domain Modules |
| 13 | +Core domain logic is organized under `src/`: |
| 14 | +- **`ingress/`**: HTTP handlers for three endpoints: |
| 15 | + - `user.rs`: Public API for bundle/transaction submission |
| 16 | + - `system.rs`: Internal API for system operations |
| 17 | + - `builder.rs`: Builder stats endpoint |
| 18 | + - Handles validation, entity scoring, rate limiting, and queuing |
| 19 | +- **`forwarder.rs`**: Relays bundles to local builder via HTTP and peer proxies via BuilderHub |
| 20 | +- **`priority/`**: Multi-level priority queue system (High/Medium/Low) |
| 21 | + - `mod.rs`: PriorityQueues implementation |
| 22 | + - `pchannel.rs`: Custom priority channels with backoff strategies |
| 23 | +- **`entity.rs`**: Entity tracking, scoring, and spam detection logic |
| 24 | +- **`rate_limit.rs`**: Per-entity rate limiting with sliding windows |
| 25 | +- **`validation.rs`**: EVM transaction validation (intrinsic gas, initcode, chain ID, EIP-4844/7702) |
| 26 | +- **`builderhub.rs`**: Peer discovery and management via BuilderHub integration |
| 27 | +- **`indexer/`**: Data persistence layer |
| 28 | + - `click/`: ClickHouse indexer with async batching |
| 29 | + - `parq.rs`: Parquet file-based storage |
| 30 | +- **`cache.rs`**: Order and signer caching with TTL-based LRU eviction |
| 31 | +- **`metrics.rs`**: Prometheus metrics for observability |
| 32 | +- **`primitives/`**: Bundle types and encoding utilities |
| 33 | +- **`jsonrpc.rs`**: JSON-RPC protocol handling |
| 34 | +- **`tasks/`**: Task execution and graceful shutdown coordination |
| 35 | + |
| 36 | +### Supporting Code |
| 37 | +- **`src/utils.rs`**: Shared helper functions |
| 38 | +- **`benches/`**: Criterion performance benchmarks |
| 39 | +- **`fixtures/`**: SQL schema files for ClickHouse tables |
| 40 | +- **`simulation/`**: Load testing harness with Docker Compose |
| 41 | +- **`tests/`**: Integration tests with reusable fixtures in `tests/common/` |
| 42 | + |
| 43 | +### Guidelines for New Code |
14 | 44 | - Place new code in the closest domain module and expose it through `lib.rs`. |
| 45 | +- For cross-cutting concerns, consider adding to `utils.rs` or creating a new focused module. |
| 46 | +- Keep modules focused and cohesive; split large modules into submodules when they exceed ~500 lines. |
15 | 47 | ## Build, Test, and Development Commands |
| 48 | + |
| 49 | +### Building |
16 | 50 | - `cargo build` compiles the binary with the default dev profile. |
| 51 | +- `cargo build --release` produces an optimized build with LTO enabled. |
| 52 | +- `just build-reproducible` creates a verifiable production build (uses the `reproducible` profile). |
17 | 53 | - `cargo run -- --help` prints the CLI flags defined in `src/cli.rs` and is the fastest smoke-test. |
18 | | -- `cargo fmt --all` applies the formatting rules in `rustfmt.toml`. |
19 | | -- `cargo clippy --all-targets --all-features -D warnings` enforces lints configured in `Cargo.toml`. |
| 54 | + |
| 55 | +### Testing |
| 56 | +- `just test` runs the test suite using nextest (faster parallel test runner). |
20 | 57 | - `cargo test` executes unit and integration tests; add `-- --nocapture` when debugging async failures. |
| 58 | +- `cargo bench` runs Criterion benchmarks (validation, signature verification, etc.). |
| 59 | +- Integration tests use `testcontainers` for ClickHouse and require Docker to be running. |
| 60 | + |
| 61 | +### Code Quality |
| 62 | +- `just fmt` or `cargo +nightly fmt --all` applies formatting rules from `rustfmt.toml`. |
| 63 | +- `just clippy` or `cargo clippy --all-targets --all-features -- -D warnings` enforces lints. |
| 64 | +- All linting configuration lives in `Cargo.toml` under `[lints.clippy]`. |
| 65 | + |
| 66 | +### Database Operations |
| 67 | +- `just provision-db` creates the ClickHouse database and tables from `fixtures/`. |
| 68 | +- `just reset-db` drops and recreates tables (destructive operation). |
| 69 | +- `just extract-data <FILE>` exports data to Parquet format. |
| 70 | + |
| 71 | +### Justfile Commands |
| 72 | +Run `just --list` to see all available commands. The justfile automates common workflows and should be the preferred method for development tasks. |
21 | 73 |
|
22 | 74 | ## Coding Style & Naming Conventions |
23 | | -- Keep Rust code within 100 columns. |
| 75 | +- Keep Rust code within 100 columns (enforced by rustfmt). |
24 | 76 | - Use `rustfmt` for formatting; it is authoritative and will reorder imports at crate granularity. |
25 | 77 | - Use `snake_case` for modules and functions, `UpperCamelCase` for types, and reserve `SCREAMING_SNAKE_CASE` for constants. |
26 | 78 | - Prefer structured errors (`thiserror`, `eyre`) over panics, and bubble fallible calls with `?`. |
27 | 79 | - When adding public APIs, gate re-exports in `lib.rs`. |
28 | | -- Document public APIs with concise rustdoc comments. |
| 80 | +- Document public APIs with concise rustdoc comments (`///` for public items). |
| 81 | +- Use `tracing::instrument` for function-level observability on hot paths and error scenarios. |
| 82 | +- Prefer immutable data structures; use `Arc` for shared ownership across async tasks. |
| 83 | +- Keep async functions small and focused; extract complex logic into sync helper functions when possible. |
29 | 84 |
|
30 | 85 | ## Testing Guidelines |
31 | | -Async flows rely on `tokio::test`, so keep helpers in `tests/common` to avoid duplication. Write integration tests alongside existing `ingress.rs` and `network.rs` files, naming functions with the behavior under test (e.g. `ingress_rejects_invalid_signature`). Run `cargo test --features ...` if you introduce optional features. New behavior must include either a targeted unit test in the owning module or an integration scenario covering success and error paths. |
| 86 | + |
| 87 | +### Test Organization |
| 88 | +- Unit tests live in the same file as the code they test, in a `#[cfg(test)]` module. |
| 89 | +- Integration tests are in the `tests/` directory, organized by feature area. |
| 90 | +- Shared test utilities and fixtures belong in `tests/common/`. |
| 91 | +- Async flows rely on `#[tokio::test]`, so ensure all async test helpers are properly propagated. |
| 92 | + |
| 93 | +### Naming Conventions |
| 94 | +Name test functions with the behavior under test, following the pattern: |
| 95 | +- `<module>_<scenario>_<expected_outcome>` |
| 96 | +- Examples: `ingress_rejects_invalid_signature`, `forwarder_retries_on_timeout`, `entity_scores_spam_bundle_low` |
| 97 | + |
| 98 | +### Test Coverage Requirements |
| 99 | +New behavior must include either: |
| 100 | +1. A targeted unit test in the owning module covering the happy path and key edge cases, OR |
| 101 | +2. An integration test scenario covering success and error paths |
| 102 | + |
| 103 | +### Running Tests |
| 104 | +- `just test` uses nextest for parallel execution (recommended). |
| 105 | +- `cargo test` for standard test runner. |
| 106 | +- `cargo test -- --nocapture` when debugging async failures or inspecting tracing output. |
| 107 | +- Run `cargo test --features ...` if you introduce optional features. |
| 108 | + |
| 109 | +### Integration Tests |
| 110 | +- Integration tests may use `testcontainers` to spin up ClickHouse for indexer tests. |
| 111 | +- Ensure Docker is running before executing integration tests. |
| 112 | +- Clean up resources in test teardown to avoid port conflicts and leaked containers. |
| 113 | + |
| 114 | +### Performance Tests |
| 115 | +- Benchmark critical paths using Criterion in `benches/`. |
| 116 | +- Focus on hot paths: validation, signature verification, entity scoring, serialization. |
| 117 | +- Run `cargo bench` to execute all benchmarks and generate performance reports. |
32 | 118 |
|
33 | 119 | ## Commit & Pull Request Guidelines |
34 | | -Follow the short, imperative style seen in history (`fix package name`); prefix with scope if it aids triage (e.g. `ingress:`). Each PR should explain motivation, outline the approach, and call out risky areas. Link to BuilderNet issues when available and attach logs or screenshots for user-facing changes. Confirm CI-ready state by running build, fmt, clippy, and tests before requesting review. |
| 120 | + |
| 121 | +### Commit Message Style |
| 122 | +- Follow the short, imperative style seen in history (e.g., `fix package name`, `add builder metrics`). |
| 123 | +- Prefix with scope if it aids triage: `ingress:`, `forwarder:`, `entity:`, `validation:`, `chore:`, `fix:`, `feat:`. |
| 124 | +- Examples: |
| 125 | + - `feat(forwarder): add retry logic for peer connections` |
| 126 | + - `fix(ingress): validate max txs per bundle` |
| 127 | + - `chore: bump version to 1.1.3` |
| 128 | + |
| 129 | +### Pull Request Requirements |
| 130 | +Each PR should include: |
| 131 | +1. **Motivation**: Why is this change needed? What problem does it solve? |
| 132 | +2. **Approach**: High-level overview of the implementation strategy. |
| 133 | +3. **Risky Areas**: Call out potential edge cases, performance impacts, or breaking changes. |
| 134 | +4. **Testing**: Describe how the change was tested (unit tests, integration tests, manual testing). |
| 135 | +5. **Issue Links**: Reference BuilderNet issues when available (e.g., `Fixes #123`). |
| 136 | +6. **Evidence**: Attach logs, metrics screenshots, or before/after comparisons for user-facing changes. |
| 137 | + |
| 138 | +### CI Readiness Checklist |
| 139 | +Before requesting review, ensure: |
| 140 | +- [ ] `cargo build` succeeds |
| 141 | +- [ ] `just fmt` produces no changes |
| 142 | +- [ ] `just clippy` passes with no warnings |
| 143 | +- [ ] `just test` passes all tests |
| 144 | +- [ ] Integration tests pass if touching ingress, indexer, or forwarder |
| 145 | + |
| 146 | +### Review Process |
| 147 | +- Address reviewer feedback promptly. |
| 148 | +- Keep commits focused; avoid mixing refactoring with feature work. |
| 149 | +- Rebase on `main` before merging to maintain a clean history. |
35 | 150 |
|
36 | 151 | ## Configuration & Runtime Notes |
37 | | -The proxy is configured through CLI flags defined in `OrderflowIngressArgs`; document any new flag, default, or environment interaction. Keep defaults safe for local testing (loopback listeners, disabled BuilderHub) and update `--help` text whenever behavior shifts. |
| 152 | + |
| 153 | +### CLI Configuration |
| 154 | +The proxy is configured through CLI flags defined in `src/cli.rs` (`OrderflowIngressArgs` struct): |
| 155 | +- **Required**: `--user-listen-url`, `--system-listen-url`, `--builder-name` |
| 156 | +- **Optional**: `--builder-url`, `--builder-hub-url`, `--orderflow-signer`, `--metrics`, etc. |
| 157 | +- All flags support environment variable overrides (e.g., `USER_LISTEN_ADDR`, `SYSTEM_LISTEN_ADDR`). |
| 158 | + |
| 159 | +### Configuration Guidelines |
| 160 | +When adding new configuration: |
| 161 | +1. Document the flag in the struct's `#[arg(...)]` annotation with clear help text. |
| 162 | +2. Choose safe defaults for local testing (loopback listeners, disabled external services). |
| 163 | +3. Update `--help` text to reflect behavior changes. |
| 164 | +4. Add validation logic in `src/runner/` if the flag affects startup behavior. |
| 165 | +5. Update this document's Configuration section if the change is significant. |
| 166 | + |
| 167 | +### Runtime Behavior |
| 168 | +- The proxy uses Tokio's multi-threaded runtime for async operations. |
| 169 | +- Jemalloc is the default allocator for better memory performance. |
| 170 | +- Graceful shutdown is coordinated through `src/tasks/` using `TaskExecutor` and `TaskManager`. |
| 171 | +- HTTP servers bind to configured addresses and serve JSON-RPC requests via Axum. |
| 172 | + |
| 173 | +### Observability |
| 174 | +- **Logs**: Structured logging via `tracing` (text or JSON format with `--log.json`). |
| 175 | +- **Metrics**: Prometheus metrics exposed at `--metrics` endpoint (default: disabled). |
| 176 | +- **Tracing**: Use `RUST_LOG` environment variable for log level control (e.g., `RUST_LOG=info,buildernet_orderflow_proxy=debug`). |
| 177 | + |
| 178 | +### Performance Considerations |
| 179 | +- Rate limiting is disabled by default; enable with `--enable-rate-limiting`. |
| 180 | +- Gzip compression is disabled by default; enable with `--http.enable-gzip`. |
| 181 | +- Indexing is optional; ClickHouse/Parquet indexers only run if configured. |
| 182 | +- Entity caches (order, signer) use LRU eviction with configurable TTLs. |
| 183 | +- Priority queues have configurable capacities and backoff strategies. |
| 184 | + |
| 185 | +## Architecture & Design Patterns |
| 186 | + |
| 187 | +### Data Flow Overview |
| 188 | +1. **Ingress** receives bundles/transactions via JSON-RPC over HTTP |
| 189 | +2. **Validation** checks transaction intrinsics, signatures, and bundle structure |
| 190 | +3. **Entity Scoring** computes priority based on sender reputation and bundle characteristics |
| 191 | +4. **Priority Queues** buffer bundles by priority level (High/Medium/Low) |
| 192 | +5. **Forwarder** distributes bundles to local builder and peer proxies |
| 193 | +6. **Indexer** persists bundles and receipts for analytics (optional) |
| 194 | + |
| 195 | +### Common Patterns |
| 196 | + |
| 197 | +#### Error Handling |
| 198 | +- Use `eyre::Result` for most fallible operations. |
| 199 | +- Use `thiserror` for domain-specific error types with context. |
| 200 | +- Log errors at appropriate levels: `error!` for unexpected failures, `warn!` for recoverable issues. |
| 201 | +- Return structured errors from public APIs; log internal errors with context. |
| 202 | + |
| 203 | +#### Async Patterns |
| 204 | +- Spawn long-running tasks using `TaskExecutor` and `TaskManager` for graceful shutdown. |
| 205 | +- Use `tokio::select!` for concurrent operations with cancellation support. |
| 206 | +- Prefer bounded channels (`tokio::sync::mpsc`) over unbounded to prevent memory growth. |
| 207 | +- Use `Arc<RwLock>` or `Arc<Mutex>` for shared mutable state; prefer immutable sharing when possible. |
| 208 | + |
| 209 | +#### Observability Patterns |
| 210 | +- Instrument public functions with `#[tracing::instrument]` for automatic span creation. |
| 211 | +- Use structured fields in log messages: `tracing::info!(entity = %addr, "processing bundle")`. |
| 212 | +- Emit metrics for critical operations: request counts, latencies, queue depths, error rates. |
| 213 | +- Add custom metrics in `src/metrics.rs` using the `metrics` crate. |
| 214 | + |
| 215 | +#### Testing Patterns |
| 216 | +- Mock external dependencies using trait abstractions (see `PeerStore` trait in `builderhub.rs`). |
| 217 | +- Use builder patterns for complex test fixtures. |
| 218 | +- Leverage `proptest` for property-based testing of validation logic. |
| 219 | +- Use `testcontainers` for integration tests requiring external services. |
| 220 | + |
| 221 | +### Key Abstractions |
| 222 | + |
| 223 | +- **`Entity`**: Represents a sender identified by signing address; tracks reputation and spam detection. |
| 224 | +- **`Priority`**: Enum for bundle priority levels (High, Medium, Low). |
| 225 | +- **`PriorityQueues`**: Multi-level queue system with per-level capacities and backoff. |
| 226 | +- **`Indexer`**: Trait for persisting bundles/receipts (implementations: ClickHouse, Parquet). |
| 227 | +- **`PeerStore`**: Trait for peer discovery (implementations: BuilderHub HTTP, local fallback). |
| 228 | + |
| 229 | +### Dependencies & Ecosystem |
| 230 | + |
| 231 | +Key dependencies and their roles: |
| 232 | +- **`alloy`**: Ethereum primitives (transactions, signatures, addresses) |
| 233 | +- **`rbuilder-primitives`**: BuilderNet-specific bundle types |
| 234 | +- **`axum`**: HTTP framework for JSON-RPC APIs |
| 235 | +- **`tokio`**: Async runtime |
| 236 | +- **`tracing`**: Structured logging and observability |
| 237 | +- **`metrics`**: Prometheus-compatible metrics collection |
| 238 | +- **`clickhouse`**: ClickHouse client for indexing |
| 239 | +- **`parquet`**: Parquet file format for indexing |
| 240 | +- **`moka`**: Async-aware LRU caching |
| 241 | +- **`criterion`**: Performance benchmarking |
| 242 | + |
| 243 | +### Performance Hotspots |
| 244 | +Monitor and optimize these areas: |
| 245 | +1. **Signature Verification**: Uses `alloy` for ECDSA recovery; consider batching. |
| 246 | +2. **Entity Scoring**: Computed per bundle; cache aggressively. |
| 247 | +3. **Validation**: Runs on every transaction; keep logic fast and allocate minimally. |
| 248 | +4. **Serialization**: JSON-RPC parsing and encoding; consider message size limits. |
| 249 | +5. **Queue Operations**: High contention on shared queues; use per-level locks. |
| 250 | + |
| 251 | +### Security Considerations |
| 252 | +- Validate all user inputs before processing (see `validation.rs`). |
| 253 | +- Rate limit by entity to prevent spam and DoS attacks. |
| 254 | +- Reject bundles from entities with low scores (spam detection). |
| 255 | +- Use TLS for peer communication (BuilderHub integration). |
| 256 | +- Sign bundles when forwarding to peers for authentication. |
| 257 | +- Never log private keys or sensitive configuration values. |
0 commit comments