evm

package
v1.0.25 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 7, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Overview

Package evm provides archival request detection heuristics.

This file contains logic to detect whether an incoming EVM JSON-RPC request requires an archival node (historical state access) WITHOUT fully unmarshalling the JSON payload. This is critical for hot-path performance.

The detection is based on analyzing:

  1. The JSON-RPC method name
  2. The block parameter value (if applicable)
  3. Comparison against the perceived current block number

Package evm provides a DataExtractor implementation for EVM-based blockchains.

The EVMDataExtractor knows how to extract quality data from EVM JSON-RPC responses:

  • Block height from eth_blockNumber responses
  • Chain ID from eth_chainId responses
  • Sync status from eth_syncing responses
  • Archival status from historical query responses (e.g., eth_getBalance)
  • Response validity from JSON-RPC structure

Index

Constants

View Source
const DefaultArchivalThreshold uint64 = 128

ArchivalThreshold is the default number of blocks behind the perceived block that triggers archival classification. Set to 128 which is a common pruning depth.

View Source
const DefaultEVMArchivalThreshold = 128

DefaultEVMArchivalThreshold is the default archival threshold for EVM-based chains. This is used by the archival heuristic to determine which requests require archival data. A block is considered "archival" if it's this many blocks behind the perceived block number.

View Source
const QoSType = "evm"

QoSType is the QoS type for the EVM blockchain.

Variables

This section is empty.

Functions

func GetArchivalMethods added in v1.0.15

func GetArchivalMethods() []string

GetArchivalMethods returns the list of methods that can potentially require archival access.

func IsArchivalRequestQuick added in v1.0.15

func IsArchivalRequestQuick(requestBody []byte) bool

IsArchivalRequestQuick is a faster variant that only checks method and basic patterns. Use this when you need maximum speed and can tolerate some false negatives. Does not require perceived block number.

Types

type ArchivalCache added in v1.0.15

type ArchivalCache struct {
	// contains filtered or unexported fields
}

ArchivalCache provides thread-safe TTL-based caching for archival endpoint status. It uses sync.RWMutex for read-heavy workloads (10-100x faster reads than regular mutex). This cache is designed to move Redis operations off the hot path by providing O(1) lookups for archival endpoint status with local memory access.

Usage:

cache := NewArchivalCache()
cache.Set("endpoint-key", true, 8*time.Hour)
isArchival, ok := cache.Get("endpoint-key")

Thread-safety: All methods are safe for concurrent use.

func NewArchivalCache added in v1.0.15

func NewArchivalCache() *ArchivalCache

NewArchivalCache creates a new ArchivalCache instance.

func (*ArchivalCache) Cleanup added in v1.0.15

func (c *ArchivalCache) Cleanup()

Cleanup removes all expired entries from the cache. Should be called periodically by a background janitor goroutine to prevent unbounded memory growth.

Typical usage:

ticker := time.NewTicker(1 * time.Hour)
go func() {
    for range ticker.C {
        cache.Cleanup()
    }
}()

func (*ArchivalCache) Delete added in v1.0.15

func (c *ArchivalCache) Delete(key string)

Delete removes a cache entry. Used for explicit invalidation when endpoint status is known to have changed.

func (*ArchivalCache) Get added in v1.0.15

func (c *ArchivalCache) Get(key string) (isArchival bool, ok bool)

Get retrieves archival status from cache. Returns (isArchival, ok) where ok indicates whether a valid (non-expired) entry exists.

Return values:

  • (true, true): Entry exists, is valid, and endpoint is archival-capable
  • (false, true): Entry exists, is valid, but endpoint is NOT archival-capable
  • (false, false): Entry missing or expired

This is the hot path method - optimized for read-heavy workloads with RLock.

func (*ArchivalCache) Len added in v1.0.15

func (c *ArchivalCache) Len() int

Len returns the number of entries in the cache (including potentially expired ones). Expired entries are cleaned up periodically by Cleanup(); between cleanups some entries may be stale, but Get() handles expiry correctly on reads.

func (*ArchivalCache) Set added in v1.0.15

func (c *ArchivalCache) Set(key string, isArchival bool, ttl time.Duration)

Set adds or updates archival status in cache with TTL. The entry will be considered expired after ttl duration from now.

Parameters:

  • key: Unique identifier for the endpoint (typically EndpointKey.String())
  • isArchival: Whether the endpoint can serve historical data
  • ttl: How long this entry remains valid (typically 8 hours matching archival expiry)

This method is called by background workers, not the hot path.

type ArchivalFilterDetails added in v1.0.15

type ArchivalFilterDetails struct {
	// IsArchival indicates if endpoint was marked as archival in local store.
	IsArchival bool
	// ExpiresAt is when the archival status expires (zero if never set).
	ExpiresAt time.Time
	// IsExpired indicates if the archival status has expired.
	IsExpired bool
	// TimeSinceExpiry is how long ago the status expired (if expired).
	TimeSinceExpiry time.Duration
	// RedisChecked indicates if Redis was consulted for archival status.
	// DEPRECATED: Kept for backward compatibility. Cache is now used instead.
	RedisChecked bool
	// RedisIsArchival is the archival status from Redis (if checked).
	// DEPRECATED: Kept for backward compatibility. Cache is now used instead.
	RedisIsArchival bool
	// CacheChecked indicates if local cache was consulted for archival status.
	CacheChecked bool
	// CacheIsArchival is the archival status from local cache (if checked).
	CacheIsArchival bool
}

ArchivalFilterDetails contains diagnostic details for archival filtering failures.

func (*ArchivalFilterDetails) ToMap added in v1.0.15

func (d *ArchivalFilterDetails) ToMap() map[string]interface{}

ToMap converts ArchivalFilterDetails to a map for error Details field.

type ArchivalHeuristic added in v1.0.15

type ArchivalHeuristic struct {
	// contains filtered or unexported fields
}

ArchivalHeuristic provides archival request detection with configurable threshold.

func NewArchivalHeuristic added in v1.0.15

func NewArchivalHeuristic(threshold uint64) *ArchivalHeuristic

NewArchivalHeuristic creates a new archival heuristic detector with the given threshold. If threshold is 0, DefaultArchivalThreshold is used.

func (*ArchivalHeuristic) IsArchivalRequest added in v1.0.15

func (h *ArchivalHeuristic) IsArchivalRequest(requestBody []byte, perceivedBlock uint64) ArchivalHeuristicResult

IsArchivalRequest determines if a JSON-RPC request requires archival data. This function is optimized for the hot path - it uses gjson to query the JSON without full unmarshalling.

Parameters:

  • requestBody: Raw JSON-RPC request bytes
  • perceivedBlock: The current perceived block number from QoS state

Returns ArchivalHeuristicResult with detection details.

type ArchivalHeuristicResult added in v1.0.15

type ArchivalHeuristicResult struct {
	// RequiresArchival indicates if the request likely needs an archival node.
	RequiresArchival bool
	// Reason provides context for the decision.
	Reason string
	// RequestedBlock is the parsed block number (0 if tag or not applicable).
	RequestedBlock uint64
	// BlockTag is the block tag if one was used (empty if numeric).
	BlockTag BlockTag
	// Method is the JSON-RPC method that was analyzed.
	Method string
}

ArchivalHeuristicResult contains the result of archival detection.

type BlockHeightConsensus added in v1.0.15

type BlockHeightConsensus struct {
	// contains filtered or unexported fields
}

BlockHeightConsensus calculates a robust perceived block height using median-anchored consensus. This protects against malicious or misconfigured endpoints reporting extremely high block numbers.

Algorithm:

  1. Track recent block observations in a sliding window
  2. Calculate median of all observations
  3. Filter out outliers: blocks > median + (syncAllowance * multiplier)
  4. Return max of filtered observations

This is self-adjusting and requires no manual configuration beyond the existing sync_allowance setting.

func NewBlockHeightConsensus added in v1.0.15

func NewBlockHeightConsensus(logger polylog.Logger, syncAllowance uint64) *BlockHeightConsensus

NewBlockHeightConsensus creates a new consensus calculator.

func (*BlockHeightConsensus) AddObservation added in v1.0.15

func (c *BlockHeightConsensus) AddObservation(endpointAddr protocol.EndpointAddr, blockHeight uint64) uint64

AddObservation adds a new block height observation and recalculates consensus. Returns the new perceived block height.

func (*BlockHeightConsensus) GetExternalBlockHeight added in v1.0.15

func (c *BlockHeightConsensus) GetExternalBlockHeight() uint64

GetExternalBlockHeight returns the current external block height floor.

func (*BlockHeightConsensus) GetMedianBlock added in v1.0.15

func (c *BlockHeightConsensus) GetMedianBlock() uint64

GetMedianBlock returns the current median block height. Returns 0 if no observations exist.

func (*BlockHeightConsensus) GetObservationCount added in v1.0.15

func (c *BlockHeightConsensus) GetObservationCount() int

GetObservationCount returns the current number of observations in the window. Useful for debugging and monitoring.

func (*BlockHeightConsensus) GetPerceivedBlock added in v1.0.15

func (c *BlockHeightConsensus) GetPerceivedBlock() uint64

GetPerceivedBlock returns the current perceived block height. This is a cached value updated on each AddObservation call.

func (*BlockHeightConsensus) SetExternalBlockGracePeriod added in v1.0.15

func (c *BlockHeightConsensus) SetExternalBlockGracePeriod(d time.Duration)

SetExternalBlockGracePeriod configures how long after creation to wait before the external block floor takes effect.

func (*BlockHeightConsensus) SetExternalBlockHeight added in v1.0.15

func (c *BlockHeightConsensus) SetExternalBlockHeight(height uint64)

SetExternalBlockHeight sets the external block height floor. If the external source reports a higher block than internal consensus, the perceived block is raised to match.

type BlockHeightFilterDetails added in v1.0.15

type BlockHeightFilterDetails struct {
	// EndpointBlock is the endpoint's reported block number.
	EndpointBlock uint64
	// PerceivedBlock is the QoS perceived block number.
	PerceivedBlock uint64
	// SyncAllowance is the configured sync allowance.
	SyncAllowance uint64
	// BlocksBehind is how many blocks the endpoint is behind.
	BlocksBehind int64
}

BlockHeightFilterDetails contains diagnostic details for block height filtering failures.

func (*BlockHeightFilterDetails) ToMap added in v1.0.15

func (d *BlockHeightFilterDetails) ToMap() map[string]interface{}

ToMap converts BlockHeightFilterDetails to a map for error Details field.

type BlockTag added in v1.0.15

type BlockTag string

BlockTag represents special block identifier tags in EVM.

const (
	BlockTagLatest    BlockTag = "latest"
	BlockTagPending   BlockTag = "pending"
	BlockTagEarliest  BlockTag = "earliest"
	BlockTagSafe      BlockTag = "safe"
	BlockTagFinalized BlockTag = "finalized"
)

type EVMDataExtractor added in v1.0.10

type EVMDataExtractor struct{}

EVMDataExtractor extracts quality data from EVM JSON-RPC responses. It knows how to parse responses from eth_blockNumber, eth_chainId, eth_syncing, etc. Uses gjson for efficient field extraction without full unmarshalling.

func NewEVMDataExtractor added in v1.0.10

func NewEVMDataExtractor() *EVMDataExtractor

NewEVMDataExtractor creates a new EVM data extractor.

func (*EVMDataExtractor) ExtractBlockHeight added in v1.0.10

func (e *EVMDataExtractor) ExtractBlockHeight(request []byte, response []byte) (int64, error)

ExtractBlockHeight extracts the block height from an eth_blockNumber response. The response result is a hex string (e.g., "0x10d4f") which is converted to int64.

Expected response format:

{"jsonrpc":"2.0","id":1,"result":"0x10d4f"}

Returns:

  • Block height as int64
  • Error if response is invalid or doesn't contain block height

func (*EVMDataExtractor) ExtractChainID added in v1.0.10

func (e *EVMDataExtractor) ExtractChainID(request []byte, response []byte) (string, error)

ExtractChainID extracts the chain identifier from an eth_chainId response. The chain ID is returned as a hex string (e.g., "0x1" for Ethereum mainnet).

Expected response format:

{"jsonrpc":"2.0","id":1,"result":"0x1"}

Returns:

  • Chain ID as hex string
  • Error if response is invalid or doesn't contain chain ID

func (*EVMDataExtractor) IsArchival added in v1.0.10

func (e *EVMDataExtractor) IsArchival(request []byte, response []byte) (bool, error)

IsArchival determines if the endpoint supports archival queries. This is typically checked by querying historical data (e.g., eth_getBalance at block 1).

An archival node will return a valid result for historical queries. A non-archival node will return an error indicating the block is too old.

Expected response format (archival):

{"jsonrpc":"2.0","id":1,"result":"0x0"}  // Balance at historical block

Expected response format (non-archival):

{"jsonrpc":"2.0","id":1,"error":{"code":-32000,"message":"missing trie node..."}}

Returns:

  • true if endpoint is archival (query succeeded)
  • false if endpoint is not archival (query failed with specific error)
  • Error if archival status cannot be determined

func (*EVMDataExtractor) IsSyncing added in v1.0.10

func (e *EVMDataExtractor) IsSyncing(request []byte, response []byte) (bool, error)

IsSyncing determines if the endpoint is currently syncing from an eth_syncing response.

eth_syncing returns:

  • false: when not syncing (node is fully synced)
  • object: when syncing (contains startingBlock, currentBlock, highestBlock)

Expected response formats:

{"jsonrpc":"2.0","id":1,"result":false}                    // Not syncing
{"jsonrpc":"2.0","id":1,"result":{"startingBlock":"0x0",...}} // Syncing

Returns:

  • true if endpoint is syncing
  • false if endpoint is synced
  • Error if sync status cannot be determined

func (*EVMDataExtractor) IsValidResponse added in v1.0.10

func (e *EVMDataExtractor) IsValidResponse(request []byte, response []byte) (bool, error)

IsValidResponse checks if the response is a valid JSON-RPC 2.0 response. This performs basic structural validation without extracting specific data.

Checks performed:

  • Valid JSON structure
  • Has "jsonrpc": "2.0"
  • Has either "result" or "error" (not both, not neither)

Returns:

  • true if response is valid JSON-RPC
  • false if response is malformed or contains JSON-RPC error
  • Error if validation fails unexpectedly

type EVMServiceQoSConfig

type EVMServiceQoSConfig interface {
	ServiceQoSConfig // Using locally defined interface to avoid circular dependency
	// contains filtered or unexported methods
}

EVMServiceQoSConfig is the configuration for the EVM service QoS.

Note: Archival capability is determined by external health checks, not by config. Health checks mark endpoints as archival-capable via UpdateFromExtractedData.

func NewEVMServiceQoSConfig

func NewEVMServiceQoSConfig(
	serviceID protocol.ServiceID,
	evmChainID string,
	supportedAPIs map[sharedtypes.RPCType]struct{},
) EVMServiceQoSConfig

NewEVMServiceQoSConfig creates a new EVM service configuration.

func NewEVMServiceQoSConfigWithSyncAllowance added in v1.0.10

func NewEVMServiceQoSConfigWithSyncAllowance(
	serviceID protocol.ServiceID,
	evmChainID string,
	supportedAPIs map[sharedtypes.RPCType]struct{},
	syncAllowance uint64,
) EVMServiceQoSConfig

NewEVMServiceQoSConfigWithSyncAllowance creates a new EVM service configuration with custom sync allowance.

type EndpointFilterError added in v1.0.15

type EndpointFilterError struct {
	// Layer identifies which filtering layer caused the rejection.
	Layer FilterLayer
	// Reason is a short, machine-readable reason code.
	Reason string
	// EndpointAddr is the endpoint that was rejected.
	EndpointAddr string
	// Details contains layer-specific diagnostic information.
	Details map[string]interface{}
	// Cause is the underlying error if any.
	Cause error
}

EndpointFilterError provides structured context about why an endpoint was filtered out. This enables operators to diagnose "no endpoints available" errors by understanding exactly which layer rejected each endpoint.

func NewArchivalFilterError added in v1.0.15

func NewArchivalFilterError(addr string, details *ArchivalFilterDetails, cause error) *EndpointFilterError

NewArchivalFilterError creates a structured error for archival filtering failures.

func NewBlockHeightFilterError added in v1.0.15

func NewBlockHeightFilterError(addr string, details *BlockHeightFilterDetails, cause error) *EndpointFilterError

NewBlockHeightFilterError creates a structured error for block height filtering failures.

func NewEndpointFilterError added in v1.0.15

func NewEndpointFilterError(layer FilterLayer, reason string, addr string, cause error, details map[string]interface{}) *EndpointFilterError

NewEndpointFilterError creates a new structured filter error.

func (*EndpointFilterError) Error added in v1.0.15

func (e *EndpointFilterError) Error() string

Error implements the error interface.

func (*EndpointFilterError) Unwrap added in v1.0.15

func (e *EndpointFilterError) Unwrap() error

Unwrap returns the underlying error for errors.Is/As support.

type EndpointSelectionMetadata

type EndpointSelectionMetadata struct {
	// RandomEndpointFallback indicates random endpoint selection when all endpoints failed validation
	RandomEndpointFallback bool
	// ValidationResults contains detailed information about each validation attempt (both successful and failed)
	ValidationResults []*qosobservations.EndpointValidationResult
}

EndpointSelectionMetadata contains metadata about the endpoint selection process.

type EndpointSelectionResult

type EndpointSelectionResult struct {
	// SelectedEndpoint is the chosen endpoint address
	SelectedEndpoint protocol.EndpointAddr
	// Metadata contains endpoint selection process metadata
	Metadata EndpointSelectionMetadata
}

EndpointSelectionResult contains endpoint selection results and metadata.

type FilterLayer added in v1.0.15

type FilterLayer string

FilterLayer identifies which filtering layer rejected an endpoint.

const (
	// FilterLayerLocalStore indicates the endpoint was rejected based on local in-memory store data.
	FilterLayerLocalStore FilterLayer = "local_store"
	// FilterLayerRedis indicates the endpoint was rejected based on Redis/shared state lookup.
	FilterLayerRedis FilterLayer = "redis"
	// FilterLayerReputation indicates the endpoint was rejected based on reputation scoring.
	FilterLayerReputation FilterLayer = "reputation"
	// FilterLayerArchival indicates the endpoint failed archival capability check.
	FilterLayerArchival FilterLayer = "archival"
)

type QoS

type QoS struct {
	// contains filtered or unexported fields
}

QoS implements ServiceQoS for EVM-based chains. It handles chain-specific:

  • Request parsing
  • Response building
  • Endpoint validation and selection

func NewSimpleQoSInstance added in v1.0.10

func NewSimpleQoSInstance(logger polylog.Logger, serviceID protocol.ServiceID) *QoS

NewSimpleQoSInstance creates a minimal EVM QoS instance without chain-specific validation. Validation (chain ID, archival checks) is now handled by active health checks. This constructor only requires the service ID and provides JSON-RPC request parsing.

func NewSimpleQoSInstanceWithSyncAllowance added in v1.0.10

func NewSimpleQoSInstanceWithSyncAllowance(logger polylog.Logger, serviceID protocol.ServiceID, syncAllowance uint64) *QoS

NewSimpleQoSInstanceWithSyncAllowance creates a minimal EVM QoS instance with custom sync allowance. Validation (chain ID, archival checks) is now handled by active health checks. If syncAllowance is 0, the default value is used.

func (QoS) ApplyObservations

func (ss QoS) ApplyObservations(observations *qosobservations.Observations) error

ApplyObservations updates endpoint storage and blockchain state from observations.

func (QoS) CheckWebsocketConnection

func (ss QoS) CheckWebsocketConnection() bool

CheckWebsocketConnection returns true if the endpoint supports Websocket connections.

func (*QoS) ConsumeExternalBlockHeight added in v1.0.15

func (qos *QoS) ConsumeExternalBlockHeight(ctx context.Context, heights <-chan int64, gracePeriod time.Duration)

ConsumeExternalBlockHeight consumes block heights from an external fetcher channel and applies them as a floor to the block consensus. This ensures that if all session endpoints are behind the real chain tip, the perceived block is corrected. Heights are also written to Redis so other replicas benefit. The gracePeriod delays applying the external floor after startup, giving suppliers time to report their block heights. Use 0 for the default (60s).

func (*QoS) GetBlockConsensusStats added in v1.0.15

func (qos *QoS) GetBlockConsensusStats() (medianBlock uint64, observationCount int)

GetBlockConsensusStats returns the median block and observation count. Used for observability to understand how block consensus is calculated.

Implements gateway.QoSBlockConsensusReporter interface.

func (*QoS) GetEndpointArchivalStatus added in v1.0.15

func (qos *QoS) GetEndpointArchivalStatus(endpointAddr protocol.EndpointAddr) (isArchival bool, expiresAt time.Time)

GetEndpointArchivalStatus returns the archival status for a specific endpoint. Returns (isArchival, expiresAt) if the endpoint has been checked for archival capability. Returns (false, zero time) if the endpoint has not been checked or is not archival-capable.

Checks both local endpointStore AND reputation service (Redis) for archival status. This ensures non-leader replicas see archival status set by health checks on the leader.

func (*QoS) GetPerceivedBlockNumber added in v1.0.12

func (qos *QoS) GetPerceivedBlockNumber() uint64

GetPerceivedBlockNumber returns the perceived current block number. Used by health checks for block height validation. Returns 0 if no block number has been observed yet. Lock-free using atomic operations.

Implements gateway.QoSService interface.

func (QoS) GetRequiredQualityChecks

func (ss QoS) GetRequiredQualityChecks(endpointAddr protocol.EndpointAddr) []gateway.RequestQoSContext

GetRequiredQualityChecks returns the list of quality checks required for an endpoint. It is called in the `gateway/hydrator.go` file on each run of the hydrator.

Note: Archival capability is determined by external health checks, not by synthetic QoS requests. The health check system marks endpoints as archival-capable via UpdateFromExtractedData when health checks pass.

func (*QoS) HydrateDisqualifiedEndpointsResponse

func (qos *QoS) HydrateDisqualifiedEndpointsResponse(serviceID protocol.ServiceID, details *devtools.DisqualifiedEndpointResponse)

HydrateDisqualifiedEndpointsResponse hydrates the disqualified endpoint response with the QoS-specific data.

  • takes a pointer to the DisqualifiedEndpointResponse
  • called by the devtools.DisqualifiedEndpointReporter to fill it with the QoS-specific data.

func (*QoS) ParseHTTPRequest

func (qos *QoS) ParseHTTPRequest(_ context.Context, req *http.Request, detectedRPCType sharedtypes.RPCType) (gateway.RequestQoSContext, bool)

ParseHTTPRequest builds a request context from an HTTP request. Returns (requestContext, true) if the request is valid JSONRPC Returns (errorContext, false) if the request is not valid JSONRPC.

Implements gateway.QoSService interface. Fallback logic for EVM: header → jsonrpc (EVM only supports JSON-RPC)

func (*QoS) ParseWebsocketRequest

func (qos *QoS) ParseWebsocketRequest(_ context.Context) (gateway.RequestQoSContext, bool)

ParseWebsocketRequest builds a request context from the provided Websocket request. Websocket connection requests do not have a body, so we don't need to parse it.

Implements gateway.QoSService interface.

func (QoS) SelectMultiple

func (ss QoS) SelectMultiple(availableEndpoints protocol.EndpointAddrList, numEndpoints uint, requestID string) (protocol.EndpointAddrList, error)

SelectMultiple returns multiple endpoint addresses from the list of available endpoints. Available endpoints are filtered based on their validity first. Endpoints are selected with TLD diversity preference when possible. If numEndpoints is 0, it defaults to 1. If numEndpoints is greater than available endpoints, it returns all valid endpoints. Note: SelectMultiple does not support archival filtering - it's used for hedge racing where we want all valid endpoints.

func (QoS) SelectMultipleWithArchival added in v1.0.15

func (ss QoS) SelectMultipleWithArchival(availableEndpoints protocol.EndpointAddrList, numEndpoints uint, requiresArchival bool, requestID string) (protocol.EndpointAddrList, error)

SelectMultipleWithArchival returns multiple endpoint addresses with optional archival filtering. When requiresArchival is true, only endpoints that have passed archival capability checks are considered. When requiresArchival is false, all valid endpoints are considered (same behavior as SelectMultiple). This enables archival requests to be routed only to archival-capable endpoints.

func (QoS) SelectWithMetadata

func (ss QoS) SelectWithMetadata(availableEndpoints protocol.EndpointAddrList, requiresArchival bool, requestID string) (EndpointSelectionResult, error)

SelectWithMetadata returns endpoint address and selection metadata. Filters endpoints by validity and captures detailed validation failure information. Selects random endpoint if all fail validation.

When requiresArchival is true, only endpoints that have passed the archival check are considered. When requiresArchival is false, the archival check is skipped, allowing all valid endpoints.

func (*QoS) SetReputationService added in v1.0.15

func (qos *QoS) SetReputationService(svc reputation.ReputationService)

SetReputationService sets the reputation service for shared state across replicas. The reputation service provides archival status via Redis, enabling non-leader replicas to access archival endpoint information set by health checks running on the leader.

func (*QoS) SetSyncAllowance added in v1.0.15

func (qos *QoS) SetSyncAllowance(syncAllowance uint64)

SetSyncAllowance dynamically updates the sync allowance for this QoS instance. This is called when external health check rules are loaded/refreshed, since those rules may specify a sync_allowance that wasn't available at QoS creation time.

func (*QoS) StartArchivalCacheRefreshWorker added in v1.0.15

func (qos *QoS) StartArchivalCacheRefreshWorker(ctx context.Context, refreshInterval time.Duration)

StartArchivalCacheRefreshWorker starts a background goroutine that periodically refreshes the archival cache from Redis. This ensures all replicas have consistent archival status without blocking the hot request path.

The refreshInterval determines how often to refresh (recommended: 2 hours, with 8-hour TTL). Call this after SetReputationService to enable cross-replica sync.

IMPORTANT: Performs immediate refresh on startup to ensure cache is warm before serving requests.

Recommended startup sequence for full cross-replica sync:

  1. qos.SetReputationService(svc)
  2. qos.StartBackgroundSync(ctx, 5*time.Second) // Perceived block number
  3. qos.StartArchivalCacheRefreshWorker(ctx, 2*time.Hour) // Archival status

func (*QoS) StartBackgroundSync added in v1.0.15

func (qos *QoS) StartBackgroundSync(ctx context.Context, syncInterval time.Duration)

StartBackgroundSync starts a background goroutine that periodically syncs perceived block number from Redis. This ensures all replicas converge to the same max block number for sync_allowance validation.

The syncInterval determines how often to check Redis (e.g., 5 seconds). Call this after SetReputationService to enable cross-replica sync.

IMPORTANT: This performs an immediate sync on startup to ensure the replica has the latest perceived block number before serving requests.

func (*QoS) UpdateFromExtractedData added in v1.0.10

func (qos *QoS) UpdateFromExtractedData(endpointAddr protocol.EndpointAddr, data *qostypes.ExtractedData) error

UpdateFromExtractedData updates QoS state from extracted observation data. Called by the observation pipeline after async parsing completes. This updates the perceived block number, archival status, and stores endpoint observations.

Implements gateway.QoSService interface.

type ServiceQoSConfig

type ServiceQoSConfig interface {
	GetServiceID() protocol.ServiceID
	GetServiceQoSType() string
}

ServiceQoSConfig defines the base interface for service QoS configurations. This avoids circular dependency with the config package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL