Skip to content

chore: increase max limit of LP rewards sampling and batch#1321

Merged
MicBun merged 3 commits into
mainfrom
LpRewardsFlow
Feb 27, 2026
Merged

chore: increase max limit of LP rewards sampling and batch#1321
MicBun merged 3 commits into
mainfrom
LpRewardsFlow

Conversation

@MicBun
Copy link
Copy Markdown
Contributor

@MicBun MicBun commented Feb 27, 2026

resolves: https://github.com/truflation/website/issues/3400

Summary by CodeRabbit

  • New Features

    • Batch LP rewards sampling now runs internally at end-of-block and supports up to 1,000 markets per run.
  • Refactor

    • Sampling now executes on all nodes via an internal end-block hook; external broadcast/signing surfaces were removed.
    • Reward computation updated to use magnitude-based distance and revised price handling.
  • Migrations

    • Configuration defaults and validations updated to reflect the increased per-run market limit.
  • Tests

    • Tests switched to trigger batched sampling helpers instead of per-market broadcasted sampling.

@MicBun MicBun self-assigned this Feb 27, 2026
@holdex
Copy link
Copy Markdown

holdex Bot commented Feb 27, 2026

Time Submission Status

Member Status Time Action Last Update
MicBun ✅ Submitted 5h Update time Feb 27, 2026, 3:39 PM

You can submit time with the command. Example:

@holdex pr submit-time 15m

See available commands to help comply with our Guidelines.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 27, 2026

📝 Walkthrough

Walkthrough

Replaces leader-only, broadcasted LP-reward sampling with an internal end-block hook that calls a new DB batch action (sample_all_active_lp_rewards), removes broadcaster/signer abstractions, increases max markets per run to 1000, updates migrations, and switches tests to batch sampling calls.

Changes

Cohort / File(s) Summary
Core extension & engine ops
extensions/tn_lp_rewards/tn_lp_rewards.go, extensions/tn_lp_rewards/internal/engine_ops.go
Removed leader-only flow, TxBroadcaster type, signer/broadcaster fields and BroadcastSampleLPRewards. Added endBlockHook and performInternalSampling; sampling now runs inline at end-block and uses maxMarkets up to 1000.
DB migrations & actions
internal/migrations/034-order-book-rewards.sql, internal/migrations/042-lp-rewards-config.sql, internal/migrations/041-settlement-config-actions.sql
Changed sample_lp_rewards visibility to PRIVATE; added sample_all_active_lp_rewards(block, market_limit) PRIVATE batch action; shifted price/distance logic to magnitude-based calculations; increased max_markets_per_run/defaults to 1000 and updated validations/docs.
Tests — sampling triggers
tests/streams/order_book/rewards_test.go, tests/streams/order_book/fee_distribution_test.go, tests/streams/order_book/fee_distribution_audit_test.go
Replaced per-market sampling helpers with triggerBatchSampling (and added triggerDirectSampling), removed signer/TxContext setup; tests now invoke batch/private action via engine-less call patterns.
Bench/types import update
internal/benchmark/types.go
Replaced testutils import with cache; changed BenchmarkCase.CacheConfig from *testutils.CacheOptions to *cache.CacheOptions.

Sequence Diagram(s)

sequenceDiagram
    participant Node as All Nodes
    participant EndBlock as End-Block Hook
    participant Engine as Engine Ops
    participant DB as Database

    Node->>EndBlock: block finalizes
    EndBlock->>EndBlock: check context & reload config
    EndBlock->>Engine: performInternalSampling(ctx, app, height, maxMarkets)
    Engine->>DB: CALL sample_all_active_lp_rewards(block, market_limit=1000)
    DB->>DB: iterate active markets (<= market_limit)
    DB->>DB: per-market sample_lp_rewards (p1/p2 magnitude, scoring)
    DB->>DB: normalize reward_percent across participants
    DB-->>Engine: result / errors
    Engine-->>EndBlock: log outcome (no error propagation)
    EndBlock-->>Node: end-block processing complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • pr-time-tracker

Poem

🐰 I hopped through tunnels of code and light,
Swapped noisy broadcasts for a calm end-of-night.
A thousand markets counted, rewards tidy and fair,
I sorted each percent with a whiskered care. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: increasing max limits for LP rewards sampling and batch operations, which is reflected across multiple files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch LpRewardsFlow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
extensions/tn_lp_rewards/internal/engine_ops.go (1)

61-72: ⚠️ Potential issue | 🟡 Minor

Inconsistent default values: maxMarkets initialized to 1000 but fallbacks return 50.

The variable is initialized to 1000 at line 65, but error/fallback paths at lines 71, 107, 109, and 112 still return 50. This creates inconsistent behavior depending on how the function exits.

🔧 Suggested fix
 func (e *EngineOperations) LoadLPRewardsConfig(ctx context.Context) (bool, int, int, error) {
 	var (
 		enabled    bool = true
 		interval   int  = 10
 		maxMarkets int  = 1000
 		found      bool
 	)

 	db, cleanup, err := e.getFreshReadTx(ctx)
 	if err != nil {
-		return true, 10, 50, fmt.Errorf("get fresh read tx: %w", err)
+		return true, 10, 1000, fmt.Errorf("get fresh read tx: %w", err)
 	}
 	defer cleanup()
 	// ... (lines 75-106)
 		if strings.Contains(msg, "lp_rewards_config") &&
 			(strings.Contains(msg, "does not exist") ||
 				strings.Contains(msg, "no such table") ||
 				strings.Contains(msg, "undefined table") ||
 				strings.Contains(msg, "not found")) {
 			e.logger.Info("lp_rewards_config table not found; using defaults")
-			return true, 10, 50, nil
+			return true, 10, 1000, nil
 		}
-		return true, 10, 50, err
+		return true, 10, 1000, err
 	}
 	if !found {
-		return true, 10, 50, nil
+		return true, 10, 1000, nil
 	}
 	return enabled, interval, maxMarkets, nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@extensions/tn_lp_rewards/internal/engine_ops.go` around lines 61 - 72, The
function LoadLPRewardsConfig has mismatched defaults: maxMarkets is initialized
to 1000 but several error/fallback returns use 50; update the function to use a
single source of truth by either changing the initial maxMarkets to 50 or
replacing hardcoded fallback returns with the maxMarkets variable (preferably
define a const like defaultMaxMarkets and use it to initialize maxMarkets and in
all return/error paths), and ensure getFreshReadTx error return and all
subsequent early returns return the same maxMarkets value alongside enabled and
interval.
internal/migrations/034-order-book-rewards.sql (1)

35-37: ⚠️ Potential issue | 🟡 Minor

Outdated documentation: action is now PRIVATE, not PUBLIC.

The comment states "Can be called by anyone (PUBLIC action)" but sample_lp_rewards was changed to PRIVATE at line 123. This documentation is now misleading.

📝 Suggested fix
 * Sampling Trigger:
-* - External system calls sample_lp_rewards($query_id, $block) periodically
-* - Recommended: Every 50 blocks (~10 minutes with 12s block times)
-* - Can be called by anyone (PUBLIC action)
+* - Internal hook calls sample_all_active_lp_rewards periodically
+* - Recommended: Every 10 blocks (configurable via lp_rewards_config)
+* - Called internally during block finalization (PRIVATE action)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/migrations/034-order-book-rewards.sql` around lines 35 - 37, Update
the top-of-file documentation to reflect that sample_lp_rewards is PRIVATE (no
longer callable by anyone); find the descriptive block mentioning "Can be called
by anyone (PUBLIC action)" and change it to indicate the action is PRIVATE
(e.g., "Can only be invoked internally (PRIVATE action)" or "Requires PRIVILEGE:
PRIVATE"), ensuring the comment matches the actual function declaration
sample_lp_rewards which was made PRIVATE.
🧹 Nitpick comments (1)
tests/streams/order_book/rewards_test.go (1)

29-31: Consider preserving error chain for better debugging.

The current error wrapping loses the original error type. Using %w would preserve the error chain.

♻️ Suggested improvement
 	if res.Error != nil {
-		return fmt.Errorf("%s", res.Error.Error())
+		return fmt.Errorf("sample_lp_rewards failed: %w", res.Error)
 	}

Same applies to line 51:

 	if res.Error != nil {
-		return fmt.Errorf("%s", res.Error.Error())
+		return fmt.Errorf("sample_all_active_lp_rewards failed: %w", res.Error)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/streams/order_book/rewards_test.go` around lines 29 - 31, The current
error wrapping in the test uses fmt.Errorf("%s", res.Error.Error()), which
discards the original error chain; change this to wrap the original error with
fmt.Errorf("...: %w", res.Error) (or otherwise return res.Error directly) in the
same block where res is checked so the original error type is preserved; apply
the same fix to the other occurrence noted (the similar check around line 51) to
keep the error chain intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@extensions/tn_lp_rewards/internal/engine_ops.go`:
- Around line 61-72: The function LoadLPRewardsConfig has mismatched defaults:
maxMarkets is initialized to 1000 but several error/fallback returns use 50;
update the function to use a single source of truth by either changing the
initial maxMarkets to 50 or replacing hardcoded fallback returns with the
maxMarkets variable (preferably define a const like defaultMaxMarkets and use it
to initialize maxMarkets and in all return/error paths), and ensure
getFreshReadTx error return and all subsequent early returns return the same
maxMarkets value alongside enabled and interval.

In `@internal/migrations/034-order-book-rewards.sql`:
- Around line 35-37: Update the top-of-file documentation to reflect that
sample_lp_rewards is PRIVATE (no longer callable by anyone); find the
descriptive block mentioning "Can be called by anyone (PUBLIC action)" and
change it to indicate the action is PRIVATE (e.g., "Can only be invoked
internally (PRIVATE action)" or "Requires PRIVILEGE: PRIVATE"), ensuring the
comment matches the actual function declaration sample_lp_rewards which was made
PRIVATE.

---

Nitpick comments:
In `@tests/streams/order_book/rewards_test.go`:
- Around line 29-31: The current error wrapping in the test uses
fmt.Errorf("%s", res.Error.Error()), which discards the original error chain;
change this to wrap the original error with fmt.Errorf("...: %w", res.Error) (or
otherwise return res.Error directly) in the same block where res is checked so
the original error type is preserved; apply the same fix to the other occurrence
noted (the similar check around line 51) to keep the error chain intact.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 022194d and 6b02ca0.

📒 Files selected for processing (7)
  • extensions/tn_lp_rewards/internal/engine_ops.go
  • extensions/tn_lp_rewards/tn_lp_rewards.go
  • internal/benchmark/types.go
  • internal/migrations/034-order-book-rewards.sql
  • tests/streams/order_book/fee_distribution_audit_test.go
  • tests/streams/order_book/fee_distribution_test.go
  • tests/streams/order_book/rewards_test.go

@MicBun MicBun changed the title chore: increase max limit of LP rewards sampling and batch lp chore: increase max limit of LP rewards sampling and batch Feb 27, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/migrations/042-lp-rewards-config.sql (1)

37-39: Table CHECK constraint does not enforce the upper bound of 1000.

The update_lp_rewards_config action validates max_markets_per_run <= 1000 (lines 111-112), but the table's CHECK constraint only enforces >= 1. Direct inserts or updates bypassing the action could store values exceeding 1000.

Consider adding the upper bound to the CHECK constraint for defense-in-depth:

Proposed fix
     CHECK (id = 1),
     CHECK (sampling_interval_blocks >= 1),
-    CHECK (max_markets_per_run >= 1)
+    CHECK (max_markets_per_run >= 1 AND max_markets_per_run <= 1000)
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/migrations/042-lp-rewards-config.sql` around lines 37 - 39, The
table CHECK constraint currently enforces CHECK (max_markets_per_run >= 1) but
not the upper bound enforced by the update_lp_rewards_config action; change the
table constraint that references max_markets_per_run to also enforce the upper
bound of 1000 (e.g. require max_markets_per_run BETWEEN 1 AND 1000 or add AND
max_markets_per_run <= 1000) so direct inserts/updates cannot exceed 1000 while
leaving the existing id and sampling_interval_blocks checks intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/migrations/042-lp-rewards-config.sql`:
- Around line 37-39: The table CHECK constraint currently enforces CHECK
(max_markets_per_run >= 1) but not the upper bound enforced by the
update_lp_rewards_config action; change the table constraint that references
max_markets_per_run to also enforce the upper bound of 1000 (e.g. require
max_markets_per_run BETWEEN 1 AND 1000 or add AND max_markets_per_run <= 1000)
so direct inserts/updates cannot exceed 1000 while leaving the existing id and
sampling_interval_blocks checks intact.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08b99a1 and 5acb8d0.

📒 Files selected for processing (2)
  • internal/migrations/041-settlement-config-actions.sql
  • internal/migrations/042-lp-rewards-config.sql

@MicBun MicBun merged commit fbb8053 into main Feb 27, 2026
6 of 8 checks passed
@MicBun MicBun deleted the LpRewardsFlow branch February 27, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant