Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix another TokenRatesController event ordering bug #1511

Merged
merged 2 commits into from
Jul 17, 2023

Conversation

Gudahtt
Copy link
Member

@Gudahtt Gudahtt commented Jul 14, 2023

Explanation

When the network switches, the TokenRatesController was relying upon the combination of two state updates (from the network controller and the tokens controller), both of which were needed in order to ensure the controller configuration was valid. These events don't arrive at the same time, meaning that the controller was potentially making one invalid call each network switch.

Additionally, there is a risk that the second event could result in no update (e.g. because the destination network isn't supported, or because there were no tokens), resulting in the data from the invalid call remaining in state.

This has been prevented by updating the controller to use the allTokens and allDetectedTokens state rather than the tokens state. A network switch now triggers a single event, and the controller configuration never enters an invalid state.

References

This tangentially relates to #1466

Changelog

@metamask/assets-controllers

  • BREAKING: The TokenRatesController now requires two new constructor parameters: selectedAddress and onPreferencesStateChange
  • Fixed: Prevent invalid TokenRatesController configuration/state upon network switching

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've highlighted breaking changes using the "BREAKING" category above as appropriate

@Gudahtt Gudahtt marked this pull request as ready for review July 14, 2023 23:46
@Gudahtt Gudahtt requested a review from a team as a code owner July 14, 2023 23:46
When the network switches, the `TokenRatesController` was relying upon
the combination of two state updates (from the network controller and
the tokens controller), both of which were needed in order to ensure
the controller configuration was valid. These events don't arrive at
the same time, meaning that the controller was potentially making one
invalid call each network switch.

Additionally, there is a risk that the second event could result in no
update (e.g. because the destination network isn't supported, or
because there were no tokens), resulting in the data from the invalid
call remaining in state.

This has been prevented by updating the controller to use the
`allTokens` and `allDetectedTokens` state rather than the `tokens`
state. A network switch now triggers a single event, and the controller
configuration never enters an invalid state.
@Gudahtt Gudahtt force-pushed the fix-another-token-rate-event-ordering-bug branch from 0a78d8d to 1cc946f Compare July 17, 2023 15:02
Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

Definitely makes more sense to keep track of tokens by chain ID rather than replace the collection each time the network is changed. Had a question that I'm curious to know the answer to before approving, but should be a quick approval after that.

@@ -203,7 +214,9 @@ export class TokenRatesController extends BaseController<
interval: 3 * 60 * 1000,
nativeCurrency: initialTicker,
chainId: initialChainId,
tokens: [],
selectedAddress: initialSelectedAddress,
allTokens: {}, // TODO: initialize these correctly, maybe as part of BaseControllerV2 migration
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm just now noticing that the only thing that TokenRatesController has in state is contractExchangeRates. Is config persisted to state and if not, shouldn't it at least be read-only? i.e. should allTokens and allDetectedTokens be a part of state too?

Copy link
Member Author

Choose a reason for hiding this comment

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

Config and state are separate; config is not persisted to-disk.

I'm not sure I follow the question about whether it should be read-only; are you talking about config or state there? What exactly should we consider making read-only and why?

I don't understand why we'd move allTokens and allDetectedTokens into state; they're already in the state of the tokens controller. That would cause an overlap.

Copy link
Contributor

Choose a reason for hiding this comment

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

By read-only, I mean that this property is only used to set the initial private state of the controller and is not changed. It seems that we are changing allTokens and allDetectedTokens throughout the lifetime of the controller, however, and that we'd want to instead use the values that come through in config to set private properties that then get changed.

Perhaps this pattern is not new, though, and config has been used as form of private state all along. I suppose it's not a big deal — this will go away when the controller is converted to BaseControllerV2 — I just didn't know if it was intentional or not.

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed, this is how config has always worked unfortunately. Agreed that it's not good. That will be fixed with the BaseControllerV2 migration

Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

Looks good!

@Gudahtt Gudahtt merged commit 6be621b into main Jul 17, 2023
91 checks passed
@Gudahtt Gudahtt deleted the fix-another-token-rate-event-ordering-bug branch July 17, 2023 17:11
MajorLift pushed a commit that referenced this pull request Oct 11, 2023
* Fix another `TokenRatesController` event ordering bug

When the network switches, the `TokenRatesController` was relying upon
the combination of two state updates (from the network controller and
the tokens controller), both of which were needed in order to ensure
the controller configuration was valid. These events don't arrive at
the same time, meaning that the controller was potentially making one
invalid call each network switch.

Additionally, there is a risk that the second event could result in no
update (e.g. because the destination network isn't supported, or
because there were no tokens), resulting in the data from the invalid
call remaining in state.

This has been prevented by updating the controller to use the
`allTokens` and `allDetectedTokens` state rather than the `tokens`
state. A network switch now triggers a single event, and the controller
configuration never enters an invalid state.

* Prevent update while polling inactive, and add tests
MajorLift pushed a commit that referenced this pull request Oct 11, 2023
* Fix another `TokenRatesController` event ordering bug

When the network switches, the `TokenRatesController` was relying upon
the combination of two state updates (from the network controller and
the tokens controller), both of which were needed in order to ensure
the controller configuration was valid. These events don't arrive at
the same time, meaning that the controller was potentially making one
invalid call each network switch.

Additionally, there is a risk that the second event could result in no
update (e.g. because the destination network isn't supported, or
because there were no tokens), resulting in the data from the invalid
call remaining in state.

This has been prevented by updating the controller to use the
`allTokens` and `allDetectedTokens` state rather than the `tokens`
state. A network switch now triggers a single event, and the controller
configuration never enters an invalid state.

* Prevent update while polling inactive, and add tests
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