Skip to main content

Overview

Provider selection in Lasso operates as a multi-stage pipeline that transforms a pool of candidate providers into an ordered execution list. The pipeline balances performance, reliability, and load distribution based on real-time health metrics and historical performance data.

Pipeline Architecture

High-Level Flow

  1. Candidate Pool: All providers configured in profile for the chain
  2. 7-Stage Filters: Exclude ineligible providers (see below)
  3. Strategy Ranking: Order by strategy (fastest, latency_weighted, etc.)
  4. Health Tiering: Reorder into 4 tiers by circuit breaker and rate limit state
  5. Execution: Sequential attempts with automatic failover

7-Stage Filter Pipeline

Implemented in Lasso.Providers.CandidateListing.list_candidates/3:

Stage 1: Transport Availability

Purpose: Filter providers based on required transport (HTTP/WebSocket) Logic:
Exclusions:
  • HTTP requests exclude providers without url
  • WebSocket requests exclude providers without active WebSocket connection
  • Checks :transport_channel_cache ETS table for WebSocket liveness

Stage 2: WebSocket Liveness

Purpose: Verify WebSocket channels are actively connected Logic:
Exclusions:
  • Providers with ws_url configured but no active connection
  • Prevents routing to providers mid-reconnection

Stage 3: Circuit Breaker State

Purpose: Exclude providers with open circuit breakers Logic:
Exclusions:
  • Providers with :open circuit breakers are always excluded
  • Providers with :half_open circuit breakers excluded unless include_half_open: true
Circuit Breaker States:
  • :closed - Healthy, provider is eligible
  • :half_open - Recovering, excluded by default (configurable)
  • :open - Failing, always excluded
See Circuit Breakers for state machine details.

Stage 4: Rate Limit State

Purpose: Optionally exclude rate-limited providers Logic:
Exclusions:
  • Only when exclude_rate_limited: true filter is set
  • Checks :lasso_instance_state ETS table for rate limit flags
  • Rate limit state is set by error classification (see error rules in profiles)
By default, rate-limited providers are not excluded, only deprioritized to Tier 2/4 during health tiering.

Stage 5: Lag Filtering

Purpose: Exclude providers that are behind consensus by more than threshold Logic:
Optimistic Lag Calculation:
Exclusions:
  • Providers with optimistic_lag < -max_lag_blocks
  • Example: max_lag_blocks: 5 excludes providers more than 5 blocks behind
  • Accounts for observation delay using block time (prevents false lag detection)
Configuration:
Example (Arbitrum - 250ms blocks, 2s poll):

Stage 6: Archival Filtering

Purpose: Require archival providers for historical queries Logic:
Exclusions:
  • Providers with archival: false when requires_archival: true
  • Typically used for eth_getLogs with historical block ranges
Configuration:

Stage 7: Exclude List

Purpose: Explicitly exclude specific providers Logic:
Exclusions:
  • Providers in the exclude filter list
  • Useful for temporary provider blacklisting
  • Used during failover to avoid retrying failed providers
Example:

Candidate Structure

Filtered candidates include metadata for downstream ranking:

Strategy Ranking

After filtering, candidates are ranked by the selected strategy:

Fastest

Ranks by measured latency (ascending):

Latency Weighted

Weighted random selection:

Load Balanced

Random shuffle:

Priority

Static priority from configuration:
See Routing Strategies for detailed strategy behavior.

Health-Based Tiering

After strategy ranking, providers are reordered into 4 tiers:

Tier Definitions

  1. Tier 1: Closed circuit + not rate-limited (preferred)
  2. Tier 2: Closed circuit + rate-limited
  3. Tier 3: Half-open circuit + not rate-limited
  4. Tier 4: Half-open circuit + rate-limited
Excluded: Open circuit providers (already filtered in Stage 3)

Tiering Logic

Tiering preserves strategy ranking within each tier:

Why Tiering Matters

Tiering ensures healthy providers receive traffic first: Scenario: 3 providers with fastest strategy
  • Provider A: 200ms latency, half-open circuit → Tier 3
  • Provider B: 350ms latency, closed circuit → Tier 1
  • Provider C: 500ms latency, closed circuit → Tier 1
Result: Provider B (350ms) receives traffic before Provider A (200ms) because it has a closed circuit.

Execution and Failover

Providers are attempted sequentially until success or exhaustion:

Sequential Execution

Success Criteria

  • 2xx HTTP status
  • Valid JSON-RPC structure
  • No RPC error code (unless expected)

Failure Handling

Retriable Errors (try next provider):
  • :rate_limit - Provider throttling
  • :network_error - Connection failure
  • :server_error - 5xx status
  • :capability_violation - Method not supported
  • :method_not_found - Method not available
Non-Retriable Errors (return immediately):
  • :invalid_params - User error
  • :user_error - Client mistake
  • :client_error - 4xx status

All Providers Exhausted

Returns 503 Service Unavailable with details:

Filter Configuration

Via Selection Filters

Via Profile Configuration

ETS State Management

The filter pipeline reads from three ETS tables:

:lasso_instance_state

Circuit Breaker State:
Rate Limit State:
Health State:

:transport_channel_cache

WebSocket Channel Liveness:

:lasso_config_store

Provider Configuration:

Performance Characteristics

Filter Pipeline Latency

Optimization Techniques

Batch Metrics Fetching:
ETS Read Concurrency:
Persistent Term Catalog:

Next Steps

Routing Strategies

Understand strategy ranking algorithms

Circuit Breakers

Learn about state machine and recovery

Profiles

Configure provider selection policies

Architecture

Explore the OTP supervision tree