Skip to content

Commit 4ea68ec

Browse files
runway-github[bot]Matt561gambinishjoaoloureirop
authored
chore(runway): cherry-pick fix: cp-7.61.0 Perps eligibility refresh race condition causing users to be incorrectly geo-blocked (#23908)
- fix: cp-7.61.0 Perps eligibility refresh race condition causing users to be incorrectly geo-blocked (#23895) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Fix race condition causing users to be geo-blocked incorrectly. The Bug: `refreshEligibility()` is called with fallback regions but isn't awaited — so the constructor continues, updates to remote config, and starts new eligibility checks. The fallback check finishes last and overwrites the correct remote result with false. Workaround: a version counter ensures stale checks (started before the config changed) are discarded when they complete. <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: fix perps refreshEligibility race condition causing users to be geo-blocked ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a version counter to blocked region config and updates refreshEligibility to ignore stale checks so fallback results don’t overwrite remote-based eligibility. > > - **PerpsController (`app/components/UI/Perps/controllers/PerpsController.ts`)**: > - **Race-condition fix for eligibility**: > - Add `blockedRegionListVersion` to version blocked region config. > - Increment version when blocked regions are set via `setBlockedRegionList` and on feature flag changes. > - Update `refreshEligibility` to capture start version and only update `state.isEligible` if the version is unchanged (including error path). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 92f5d33. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Nicholas Gambino <nicholas.gambino@consensys.net> [fa1b19f](fa1b19f) Co-authored-by: Matthew Grainger <46547583+Matt561@users.noreply.github.com> Co-authored-by: Nicholas Gambino <nicholas.gambino@consensys.net> Co-authored-by: João Loureiro <175489935+joaoloureirop@users.noreply.github.com>
1 parent 2a2aeb1 commit 4ea68ec

File tree

1 file changed

+32
-6
lines changed

1 file changed

+32
-6
lines changed

app/components/UI/Perps/controllers/PerpsController.ts

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,14 @@ export class PerpsController extends BaseController<
633633
source: 'fallback',
634634
};
635635

636+
/**
637+
* Version counter for blocked region list.
638+
* Used to prevent race conditions where stale eligibility checks
639+
* (started with fallback config) overwrite results from newer checks
640+
* (started with remote config).
641+
*/
642+
private blockedRegionListVersion = 0;
643+
636644
// Store HIP-3 configuration (mutable for runtime updates from remote flags)
637645
private hip3Enabled: boolean;
638646
private hip3AllowlistMarkets: string[];
@@ -713,6 +721,7 @@ export class PerpsController extends BaseController<
713721
newSource: 'remote' | 'fallback',
714722
) => {
715723
this.blockedRegionList = { list: newList, source: newSource };
724+
this.blockedRegionListVersion += 1;
716725
},
717726
refreshEligibility: () => this.refreshEligibility(),
718727
}),
@@ -739,6 +748,7 @@ export class PerpsController extends BaseController<
739748
source: 'remote' | 'fallback',
740749
) => {
741750
this.blockedRegionList = { list, source };
751+
this.blockedRegionListVersion += 1;
742752
},
743753
refreshEligibility: () => this.refreshEligibility(),
744754
getHip3Config: () => ({
@@ -2099,13 +2109,25 @@ export class PerpsController extends BaseController<
20992109
* Refresh eligibility status
21002110
*/
21012111
async refreshEligibility(): Promise<void> {
2102-
try {
2103-
DevLogger.log('PerpsController: Refreshing eligibility');
2112+
// Capture the current version before starting the async operation.
2113+
// This prevents race conditions where stale eligibility checks
2114+
// (started with fallback config) overwrite results from newer checks
2115+
// (started with remote config after it was fetched).
2116+
const versionAtStart = this.blockedRegionListVersion;
21042117

2118+
try {
2119+
// TODO: It would be good to have this location before we call this async function to avoid the race condition
21052120
const isEligible = await EligibilityService.checkEligibility(
21062121
this.blockedRegionList.list,
21072122
);
21082123

2124+
// Only update state if the blocked region list hasn't changed while we were awaiting.
2125+
// This prevents stale fallback-based eligibility checks from overwriting
2126+
// results from remote-based checks.
2127+
if (this.blockedRegionListVersion !== versionAtStart) {
2128+
return;
2129+
}
2130+
21092131
this.update((state) => {
21102132
state.isEligible = isEligible;
21112133
});
@@ -2114,10 +2136,14 @@ export class PerpsController extends BaseController<
21142136
ensureError(error),
21152137
this.getErrorContext('refreshEligibility'),
21162138
);
2117-
// Default to eligible on error
2118-
this.update((state) => {
2119-
state.isEligible = true;
2120-
});
2139+
2140+
// Only update on error if version is still current
2141+
if (this.blockedRegionListVersion === versionAtStart) {
2142+
// Default to eligible on error
2143+
this.update((state) => {
2144+
state.isEligible = true;
2145+
});
2146+
}
21212147
}
21222148
}
21232149

0 commit comments

Comments
 (0)