Skip to content

Optimize authority_checker hot paths for transaction authorization#258

Open
heifner wants to merge 3 commits intomasterfrom
feature/auth-checker-optimizations
Open

Optimize authority_checker hot paths for transaction authorization#258
heifner wants to merge 3 commits intomasterfrom
feature/auth-checker-optimizations

Conversation

@heifner
Copy link
Copy Markdown
Contributor

@heifner heifner commented Mar 17, 2026

Summary

  • Fast-path for single-key authorities (~37% faster): Bypasses meta_permission_map allocation and rollback overhead for the most common case (single key, no account references)
  • Fast-path for threshold-1 multi-key authorities (~46% faster): Handles 1-of-N configurations (e.g. 1-of-3 active) by returning on first matching key without rollback overhead
  • Binary search for key matching (up to 55% faster for large key sets): Replaces linear boost::find with std::lower_bound on the already-sorted provided_keys vector
  • flat_map permission cache: Switches permission_cache_type from std::map to flat_map for better cache locality with typical small permission sets
  • Short-circuit irrelevant-auth check: Skips redundant DB lookups and hierarchy walks in authorization_manager::check_authorization when declared permission name matches the minimum (the common case)
  • Auth benchmark suite: New benchmark covering single-key, multi-sig, large key sets, and recursive permission resolution scenarios

Benchmark Results (Release build, 10k runs, minimum ns)

Benchmark Before After Change
auth_single_key 61 ns 39 ns -36%
auth_single_key_fail 62 ns 35 ns -44%
auth_multisig_1of3 ~79 ns 43 ns -46%
auth_multisig_2of3 79 ns 83 ns +5%
auth_multisig_3of5 104 ns 109 ns +5%
auth_search_in_50_keys 272 ns 164 ns -40%
auth_10keys_in_50_provided 853 ns 379 ns -56%
auth_recursive_2_level 128 ns 118 ns -8%
auth_recursive_3_level 215 ns 214 ns ~0%

Multi-sig 2-of-3/3-of-5 show a small ~5% regression from std::lower_bound's operator< vs boost::find's operator== at small N. The absolute cost increase is ~4-5ns, dwarfed by the gains on the dominant single-key and threshold-1 paths.

- Add fast-path for single-key authorities (most common case), bypassing
  meta_permission_map allocation and rollback overhead (~37% faster)
- Add fast-path for threshold-1 multi-key authorities (e.g. 1-of-3),
  returning on first matching key (~46% faster)
- Replace linear key search (boost::find) with binary search
  (std::lower_bound) on the already-sorted provided_keys vector,
  yielding up to 55% improvement for large key sets
- Switch permission_cache_type from std::map to flat_map for better
  cache locality with typical small permission sets
- Short-circuit irrelevant-auth check in authorization_manager when
  declared permission name matches the minimum, avoiding redundant
  DB lookups and hierarchy walks on the most common code path
- Add resolve_key() helper for type-safe shared_public_key conversion
- Add auth benchmark suite covering single-key, multi-sig, large key
  sets, and recursive permission resolution scenarios
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes hot paths in authority_checker and related authorization checks to reduce transaction authorization overhead, and adds a dedicated authorization benchmark suite to track performance changes.

Changes:

  • Add fast paths for common key-only authorities and switch key matching to binary search over sorted provided_keys.
  • Replace the permission cache from std::map to flat_map and adjust recursion logic to handle iterator invalidation.
  • Add an auth benchmark feature with scenarios covering single-key, multisig, large key sets, and recursive resolution.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
libraries/chain/include/sysio/chain/authority_checker.hpp Adds fast paths, binary-search key lookup, and changes permission cache to flat_map.
libraries/chain/authorization_manager.cpp Skips irrelevant-auth hierarchy checks when declared permission already equals the minimum.
benchmark/benchmark.hpp Declares auth_benchmarking() entry point.
benchmark/benchmark.cpp Registers auth as a runnable benchmark feature.
benchmark/auth.cpp Implements new authorization microbenchmarks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +236 to +243
// Re-lookup after recursive call (flat_map iterators may be invalidated)
auto cache_itr = cached_permissions.find( permission.permission );
assert( cache_itr != cached_permissions.end() );
if( r ) {
total_weight += permission.weight;
itr->second = permission_satisfied;
cache_itr->second = permission_satisfied;
} else {
itr->second = permission_unsatisfied;
cache_itr->second = permission_unsatisfied;
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

assert(cache_itr != cached_permissions.end()) is used in this header without including <cassert>, which can cause compilation failures depending on include order. Also, in Release builds with NDEBUG, the assert is compiled out and cache_itr->second = ... would be undefined behavior if the lookup ever failed; prefer a non-elided check (e.g., SYS_ASSERT/SYS_THROW) or an explicit if (cache_itr == end) ... fallback, and add the proper header if you keep assert.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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