Skip to content

Implement hour-aligned caching for eth_gasPrice #4589

@quiet-node

Description

@quiet-node

Overview

Currently, eth_gasPrice does not use caching (removed in hotfix #4583). This was necessary because the previous 15-minute cache TTL was misaligned with Hedera's hourly gas price updates, causing stale values to be returned to clients like MetaMask.

Network fees from the Mirror Node change on clock hour boundaries (e.g., 13:00:00, 14:00:00). To optimize performance while maintaining accuracy, we need a caching strategy that aligns cache expiration with these hourly boundaries.

Proposed Solution

Implement dynamic TTL caching that expires gas prices at the next hour boundary plus a small buffer:

  1. Calculate expiration time: When eth_gasPrice is called, calculate TTL as the time remaining until the next clock hour + buffer seconds

    • Example: Request at 13:59:00 → cache until 14:00:0x (where x is buffer, e.g., 1-3 seconds)
    • Example: Request at 14:01:00 → cache until 15:00:0x
  2. Implementation approach:

    • Modify the gasPrice() method in CommonService to use a custom caching strategy
    • Calculate dynamic TTL: ttl = (3600 - (currentTimeSeconds % 3600)) + bufferSeconds
    • Apply cache with the calculated TTL instead of a fixed duration
  3. Clock drift buffer: Add a configurable buffer (default 1-3 seconds) to account for potential clock drift between servers

Considerations

Critical Edge Case: Cache Miss After Hour Boundary

Problem: On cache miss at 14:00:01, if Mirror Node hasn't updated yet, the relay caches the old price with TTL of ~1 hour, recreating the original hotfix bug. This only affects the first request after hour boundaries, but impact is severe (full hour of stale data causing transaction failures).

Note: Cache hits are unaffected—old values expire within x buffer seconds as designed.

Recommended Fix: Implement minimum TTL threshold (X seconds). Skip caching if calculated_ttl > 3600 - threshold, forcing fresh fetch during Mirror Node update windows while maintaining performance for remaining ~59 minutes.

Example:

const MIN_CACHE_THRESHOLD = X; // x seconds (TBD)
const timeUntilNextHour = 3600 - (currentSeconds % 3600);
const calculatedTTL = timeUntilNextHour + bufferSeconds;

if (calculatedTTL > 3600 - MIN_CACHE_THRESHOLD) {
  // Within X after hour boundary (14:00:00 - 14:00:0X)
  // Don't cache, return fresh value directly
  // Ensure we fetch latest from Mirror Node during this "danger window"
  return await fetchFromMirrorNode();
}

// Safe to cache for remaining time
return await cacheWithTTL(calculatedTTL);

Related Issues

Follow-up to hotfix #4583 which removed caching to resolve MetaMask failures

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions