Skip to content

starknet_api: Add configurable hash memoization - #3

Open
heemankv wants to merge 4 commits into
madara-apollo-0.14.2-rc.7-fixfrom
perf/blockifier-hash-cache-runtime-config
Open

heemankv wants to merge 4 commits into
madara-apollo-0.14.2-rc.7-fixfrom
perf/blockifier-hash-cache-runtime-config

Conversation

@heemankv

@heemankv heemankv commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add opt-in memoization for four deterministic Starknet API hash operations
  • expose one startup configuration with independent capacities for Starknet Keccak, Pedersen pair, Pedersen array, and Poseidon array caches
  • expose cumulative per-kind total-call, hit, miss, and capacity-clear snapshots so downstream Madara telemetry can calculate hit and miss percentages without adding OpenTelemetry work to the hash hot path
  • keep the caches disabled by default and clear entries whenever they are disabled or reconfigured
  • retain the existing set_hash_cache_enabled(bool) API for compatibility

Exact Madara dependency base

This PR is intentionally based on 4251763b664ee50a76889a800b801627f31bfd1c, the commit tagged APOLLO-0.14.2-RC.7-fix.

That is the exact Sequencer revision used by madara-alliance/madara@daaacf0055fbea1dca67b49aab5a74426efbf49c before applying this patch. The PR base branch points directly to that tag commit, so the diff remains limited to the hash-cache work needed by Madara.

Validation

  • cargo test -p starknet_api hash_cache::tests: 2 passed
  • configuration test covers runtime capacities, total calls, hit/miss counters, capacity clears, and bounded entries
  • git diff --check: passed
  • downstream locked cargo check -p mc-exec and cargo check -p madara: passed

Downstream integration: madara-alliance/madara#1250

@heemankv heemankv changed the title perf(starknet-api): add configurable hash memoization starknet_api: Add configurable hash memoization Aug 31, 2026
@heemankv
heemankv force-pushed the perf/blockifier-hash-cache-runtime-config branch from 1a41bf8 to 9a4336d Compare August 31, 2026 17:10

@Mohiiit Mohiiit left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left one non-blocking maintainability suggestion in the inline comment.

}

static HASH_CACHE_ENABLED: AtomicBool = AtomicBool::new(false);
static SN_KECCAK_CACHE_CAPACITY: AtomicUsize = AtomicUsize::new(DEFAULT_SN_KECCAK_CACHE_CAPACITY);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth grouping each cache’s map, capacity, and counters into a small generic type? These are currently maintained as parallel statics and passed independently into get, insert, and snapshot, so their association is enforced by convention rather than by the type.

For example:

struct HashCache<K> {
    entries: DashMap<K, Felt>,
    capacity: AtomicUsize,
    counters: CacheCounters,
}

impl<K> HashCache<K>
where
    K: Eq + Hash,
{
    fn get<Q>(&self, key: &Q) -> Option<Felt>
    where
        K: Borrow<Q>,
        Q: Eq + Hash + ?Sized,
    {
        // Existing lookup and metrics behavior.
    }

    fn insert(&self, key: K, value: Felt) {
        // Existing capacity and insertion behavior.
    }

    fn clear(&self) { /* ... */ }

    fn snapshot(&self, kind: HashCacheKind) -> HashCacheMetrics {
        /* ... */
    }
}

static SN_KECCAK_CACHE: LazyLock<HashCache<Vec<u8>>> =
    LazyLock::new(|| HashCache::new(DEFAULT_SN_KECCAK_CACHE_CAPACITY));

The domain-specific sn_keccak_get/insert and array helpers could remain, while delegating to methods on their cache. This would keep the current explicit call sites but make it impossible to accidentally pair a map with the wrong capacity or counters. I don’t think this needs a custom trait unless multiple cache implementations are expected.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bumping this once: I don't think this suggestion has been addressed yet. The cache map, capacity, and counters are still separate parallel statics, and the lookup, insertion, and snapshot helpers still receive them independently. The new Blockifier executor-counter commit is separate from this area. This remains non-blocking from my side.

@heemankv
heemankv force-pushed the perf/blockifier-hash-cache-runtime-config branch from a022573 to 4c5fd9e Compare September 1, 2026 11:33

@Mohiiit Mohiiit left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. The remaining cache-encapsulation suggestion is non-blocking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants