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

feat(wallet)_: Auto refresh token list #6399

Open
wants to merge 4 commits into
base: feat/add-auto-refresh-option-to-settings
Choose a base branch
from

Conversation

saledjenic
Copy link
Contributor

@saledjenic saledjenic commented Mar 7, 2025

This PR depends on:

Changes in this PR are not breaking changes and include the following:

  • Fetching the list of tokens lists from remote, if the remote URL is not provided a local, hardcoded list will be used.
  • Fetching the content of each remote list from the list of URLs (each URL points to a single tokens list).
  • At this moment, updating the tokens lists is scheduled every 30 minutes, while the interval for checking for the update is set to every 3 minutes. The client should set the refresh interval, which will be added in one of the follow-up PRs.
  • Old token stores are removed, and new, initial token lists, following the new form, are added.
  • According to the previous point, scripts used by make commands download-tokens and analyze-token-stores are updated.
  • The above-mentioned changes are integrated into token.Manager type.
  • Each time tokens lists are update the wallet.token-lists.updated signal will be emitted

@saledjenic saledjenic force-pushed the feat/add-auto-refresh-option-to-settings branch from 763a01b to 7c986fc Compare March 7, 2025 14:00
@status-im-auto
Copy link
Member

status-im-auto commented Mar 7, 2025

Jenkins Builds

Click to see older builds (82)
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ 00e797d #1 2025-03-07 14:00:15 ~2 min android 📦aar
✔️ 00e797d #1 2025-03-07 14:00:17 ~2 min ios 📦zip
✔️ 00e797d #1 2025-03-07 14:01:26 ~4 min macos 📦zip
✔️ 00e797d #1 2025-03-07 14:03:10 ~5 min windows 📦zip
✔️ 00e797d #1 2025-03-07 14:03:35 ~6 min macos 📦zip
✔️ 00e797d #1 2025-03-07 14:03:45 ~6 min linux 📦zip
✔️ 00e797d #1 2025-03-07 14:16:46 ~19 min tests-rpc 📄log
✖️ 00e797d #1 2025-03-07 14:29:22 ~31 min tests 📄log
✔️ 05c6026 #2 2025-03-07 14:04:06 ~3 min android 📦aar
✔️ 05c6026 #2 2025-03-07 14:04:18 ~3 min ios 📦zip
✔️ 05c6026 #2 2025-03-07 14:06:45 ~5 min macos 📦zip
✔️ 05c6026 #2 2025-03-07 14:06:54 ~3 min windows 📦zip
✔️ 05c6026 #2 2025-03-07 14:08:59 ~5 min macos 📦zip
✔️ 05c6026 #2 2025-03-07 14:09:19 ~5 min linux 📦zip
✔️ 05c6026 #2 2025-03-07 14:33:02 ~16 min tests-rpc 📄log
✖️ 05c6026 #2 2025-03-07 14:59:31 ~30 min tests 📄log
✖️ e78b98d #3 2025-03-07 21:52:56 ~2 min tests 📄log
✔️ e78b98d #3 2025-03-07 21:53:12 ~2 min android 📦aar
✔️ e78b98d #3 2025-03-07 21:53:21 ~2 min ios 📦zip
✔️ e78b98d #3 2025-03-07 21:54:31 ~4 min windows 📦zip
✔️ e78b98d #3 2025-03-07 21:55:00 ~4 min macos 📦zip
✔️ e78b98d #3 2025-03-07 21:55:32 ~5 min macos 📦zip
✔️ e78b98d #3 2025-03-07 21:55:50 ~5 min linux 📦zip
✔️ e78b98d #3 2025-03-07 22:05:56 ~15 min tests-rpc 📄log
✔️ 7afb773 #4 2025-03-10 10:26:02 ~2 min android 📦aar
✔️ 7afb773 #4 2025-03-10 10:26:09 ~3 min ios 📦zip
✔️ 7afb773 #4 2025-03-10 10:27:05 ~3 min windows 📦zip
✔️ 7afb773 #4 2025-03-10 10:27:45 ~4 min macos 📦zip
✔️ 7afb773 #4 2025-03-10 10:28:28 ~5 min linux 📦zip
✔️ 7afb773 #4 2025-03-10 10:29:25 ~6 min macos 📦zip
✔️ 7afb773 #4 2025-03-10 10:40:08 ~16 min tests-rpc 📄log
✖️ 7afb773 #4 2025-03-10 10:55:05 ~31 min tests 📄log
✔️ 6ae05dd #5 2025-03-10 12:39:19 ~2 min ios 📦zip
✔️ 6ae05dd #5 2025-03-10 12:39:36 ~2 min android 📦aar
✔️ 6ae05dd #5 2025-03-10 12:40:31 ~3 min windows 📦zip
✔️ 6ae05dd #5 2025-03-10 12:41:18 ~4 min macos 📦zip
✔️ 6ae05dd #5 2025-03-10 12:41:50 ~5 min macos 📦zip
✔️ 6ae05dd #5 2025-03-10 12:42:23 ~5 min linux 📦zip
✔️ 6ae05dd #5 2025-03-10 12:53:58 ~17 min tests-rpc 📄log
✖️ 6ae05dd #5 2025-03-10 13:06:56 ~30 min tests 📄log
✔️ c7f1074 #6 2025-03-10 13:31:23 ~3 min android 📦aar
✔️ c7f1074 #6 2025-03-10 13:31:24 ~3 min ios 📦zip
✔️ c7f1074 #6 2025-03-10 13:32:21 ~3 min windows 📦zip
✔️ c7f1074 #6 2025-03-10 13:32:55 ~4 min macos 📦zip
✔️ c7f1074 #6 2025-03-10 13:33:36 ~5 min macos 📦zip
✔️ c7f1074 #6 2025-03-10 13:34:18 ~5 min linux 📦zip
✔️ c7f1074 #6 2025-03-10 13:45:22 ~16 min tests-rpc 📄log
✖️ c7f1074 #6 2025-03-10 13:58:36 ~30 min tests 📄log
✔️ a0f246a #7 2025-03-10 14:00:16 ~2 min ios 📦zip
✔️ a0f246a #7 2025-03-10 14:00:38 ~3 min android 📦aar
✔️ a0f246a #7 2025-03-10 14:01:19 ~3 min macos 📦zip
✔️ a0f246a #7 2025-03-10 14:01:59 ~4 min windows 📦zip
✔️ a0f246a #7 2025-03-10 14:02:42 ~5 min linux 📦zip
✔️ a0f246a #7 2025-03-10 14:04:19 ~6 min macos 📦zip
✔️ a0f246a #7 2025-03-10 14:16:23 ~18 min tests-rpc 📄log
✖️ a0f246a #7 2025-03-10 14:29:15 ~30 min tests 📄log
✔️ 2d970fe #8 2025-03-10 14:20:16 ~3 min ios 📦zip
✔️ 2d970fe #8 2025-03-10 14:21:41 ~4 min android 📦aar
✔️ 2d970fe #8 2025-03-10 14:21:50 ~4 min macos 📦zip
✔️ 2d970fe #8 2025-03-10 14:22:49 ~5 min windows 📦zip
✔️ 2d970fe #8 2025-03-10 14:23:21 ~6 min macos 📦zip
✔️ 2d970fe #8 2025-03-10 14:24:54 ~7 min linux 📦zip
✔️ 2d970fe #8 2025-03-10 14:39:07 ~21 min tests-rpc 📄log
✖️ 2d970fe #8 2025-03-10 14:59:59 ~30 min tests 📄log
✖️ 2d970fe #9 2025-03-10 15:42:31 ~31 min tests 📄log
✔️ 7408f84 #9 2025-03-11 07:59:51 ~2 min android 📦aar
✔️ 7408f84 #9 2025-03-11 08:00:03 ~3 min ios 📦zip
✔️ 7408f84 #9 2025-03-11 08:01:12 ~4 min windows 📦zip
✔️ 7408f84 #9 2025-03-11 08:01:36 ~4 min macos 📦zip
✔️ 7408f84 #9 2025-03-11 08:02:14 ~5 min macos 📦zip
✔️ 7408f84 #9 2025-03-11 08:03:10 ~6 min linux 📦zip
✔️ 7408f84 #9 2025-03-11 08:14:02 ~17 min tests-rpc 📄log
✖️ 7408f84 #10 2025-03-11 08:27:59 ~30 min tests 📄log
✖️ 7408f84 #11 2025-03-11 09:09:54 ~29 min tests 📄log
✔️ 77acac4 #10 2025-03-14 07:44:27 ~2 min ios 📦zip
✔️ 77acac4 #10 2025-03-14 07:44:35 ~3 min android 📦aar
✔️ 77acac4 #10 2025-03-14 07:45:46 ~4 min windows 📦zip
✔️ 77acac4 #10 2025-03-14 07:46:03 ~4 min macos 📦zip
✔️ 77acac4 #10 2025-03-14 07:46:41 ~5 min macos 📦zip
✔️ 77acac4 #10 2025-03-14 07:47:43 ~6 min linux 📦zip
✔️ 77acac4 #10 2025-03-14 08:01:57 ~20 min tests-rpc 📄log
✖️ 77acac4 #12 2025-03-14 08:15:43 ~34 min tests 📄log
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ 056ebaf #11 2025-03-14 12:33:58 ~3 min android 📦aar
✔️ 056ebaf #11 2025-03-14 12:34:05 ~3 min ios 📦zip
✔️ 056ebaf #11 2025-03-14 12:35:25 ~4 min windows 📦zip
✔️ 056ebaf #11 2025-03-14 12:35:35 ~4 min macos 📦zip
✔️ 056ebaf #11 2025-03-14 12:36:12 ~5 min macos 📦zip
✔️ 056ebaf #11 2025-03-14 12:36:52 ~5 min linux 📦zip
✔️ 056ebaf #11 2025-03-14 12:52:10 ~21 min tests-rpc 📄log
✔️ 056ebaf #13 2025-03-14 13:07:00 ~36 min tests 📄log
✔️ bce20bd #12 2025-03-14 13:47:41 ~3 min ios 📦zip
✔️ bce20bd #12 2025-03-14 13:47:50 ~3 min android 📦aar
✔️ bce20bd #12 2025-03-14 13:48:44 ~3 min windows 📦zip
✔️ bce20bd #12 2025-03-14 13:49:22 ~4 min macos 📦zip
✔️ bce20bd #12 2025-03-14 13:49:57 ~5 min macos 📦zip
✔️ bce20bd #12 2025-03-14 13:50:41 ~6 min linux 📦zip
✔️ bce20bd #12 2025-03-14 14:05:12 ~20 min tests-rpc 📄log
✔️ bce20bd #14 2025-03-14 14:19:10 ~34 min tests 📄log

@saledjenic saledjenic force-pushed the auto-refresh-token-list branch from 00e797d to 05c6026 Compare March 7, 2025 14:00
@saledjenic saledjenic force-pushed the feat/add-auto-refresh-option-to-settings branch from 7c986fc to 28bf764 Compare March 10, 2025 10:13
@saledjenic saledjenic force-pushed the auto-refresh-token-list branch 4 times, most recently from c7f1074 to a0f246a Compare March 10, 2025 13:57
@saledjenic saledjenic force-pushed the auto-refresh-token-list branch from a0f246a to 2d970fe Compare March 10, 2025 14:16
@saledjenic saledjenic changed the title Auto refresh token list feat(wallet)_: Auto refresh token list Mar 10, 2025
@saledjenic saledjenic marked this pull request as ready for review March 10, 2025 15:11
@saledjenic saledjenic requested review from a team as code owners March 10, 2025 15:11
@saledjenic saledjenic force-pushed the auto-refresh-token-list branch from 2d970fe to 7408f84 Compare March 11, 2025 07:56
// If the remote list url is not set (empty string provided), the hardcoded default list will be used.
// The auto-refresh interval is used to fetch the list of token lists from the remote source and update the local cache.
// The auto-refresh check interval is used to check if the auto-refresh should be triggered.
func (t *TokenLists) Start(remoteListUrl string, autoRefreshInterval time.Duration, autoRefreshCheckInterval time.Duration) {
Copy link
Contributor

@friofry friofry Mar 13, 2025

Choose a reason for hiding this comment

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

Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it, - documentation for context

https://zealous-polka-dc7.notion.site/Code-smell-2-Pass-context-to-functions-cd49904001ca4152be006124e64f5c61

This approach isn't ideal because contexts in Go are meant to flow down from the top (entry point) of the application. Each component typically receives a context parameter from its caller, rather than generating a new background context internally. Ideally, we would refactor so that: Add a context parameter to the wallet.Start() function. This ensures the caller explicitly controls the lifecycle and cancellation of routines.
Eventually, we might(should) manage a single "root context" at the StatusNode (get_status_node.go) level (the top-level entry point). This would allow coordinated cancellation of all services (30 services at the moment) at shutdown.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@friofry I agree, but that requires refactoring of the upper code. If I just remove it from the struct I won't be able to cancel the context on calling Stop(). I've added "todo" and will try to address that in the follow-up PR.

{
"id": "uniswap",
"sourceUrl": "https://ipfs.io/ipns/tokens.uniswap.org",
"schema": "https://uniswap.org/tokenlist.schema.json"
Copy link
Contributor

Choose a reason for hiding this comment

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

is this a valid URL ?

 curl -X GET https://ipfs.io/ipns/tokens.uniswap.org
curl: (35) Recv failure: Operation timed out

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't see any issues here. Also, trying this command returns an instant response on my side.

Copy link
Contributor

Choose a reason for hiding this comment

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

We have many users in different countries.
Probably making this data available from our market proxy will allow us to solve this problem.

}

func downloadTokens(client *http.Client, key string, source defaulttokenlists.TokensSource) {
response, err := client.Get(source.SourceURL)
Copy link
Contributor

Choose a reason for hiding this comment

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

Token list sounds like a big chunk of data that rarely change.
I suggest optimizing it:

  • store etag header for the downloaded token list. And do not download what we already have. (If-None-Match: or If-Modified-Since and do not download if returns 304)
  • Introduction of context cancellation of HTTP request
  • Addition of connection and request timeouts against hanging requests
func fetchContentWithCaching(ctx context.Context, url string, etag string) ([]byte, string, bool, error) {
    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    if err != nil {
        return nil, "", false, err
    }
    
    // ETag 
    if etag != "" {
        req.Header.Add("If-None-Match", etag)
    }
    
    // Timeouts
    transport := &http.Transport{
	DialContext: (&net.Dialer{
		Timeout: dialTimeout, // Timeout for establishing a connection
	}).DialContext,
	TLSHandshakeTimeout:   tlsHandshakeTimeout,   // Timeout for TLS handshake
	ResponseHeaderTimeout: responseHeaderTimeout, // Timeout for receiving response headers
    }

    client := &http.Client{
        Transport: transport,
        Timeout: requesetTimeout * time.Second,
    }
    
    resp, err := client.Do(req)
    if err != nil {
        return nil, "", false, err
    }
    defer resp.Body.Close()
    
    // HTTP 304 Not Modified
    if resp.StatusCode == http.StatusNotModified {
        return nil, etag, true, nil
    }
    
    // Content changed
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, "", false, err
    }
    
    // update ETag
    newEtag := resp.Header.Get("ETag")
    if newEtag == "" {
        newEtag = etag // if etag is missing
    }
    
    return body, newEtag, false, nil
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like this idea. Will do it today in the follow-up PR.

Actually, I see now that we have thirdparty.NewHTTPClientWithDetailedTimeouts and will extend it with the new function func fetchContentWithCaching(ctx context.Context, url string, etag string) ([]byte, string, bool, error) and use it from there in a new PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

Cool! It would be great to use the same http client

@saledjenic saledjenic force-pushed the feat/add-auto-refresh-option-to-settings branch from 28bf764 to fc68b55 Compare March 13, 2025 13:20
@saledjenic saledjenic force-pushed the auto-refresh-token-list branch from 7408f84 to 77acac4 Compare March 14, 2025 07:41
@saledjenic
Copy link
Contributor Author

@friofry thanks for the review and good comments. The last commit is about the changes you proposed. Once you agree I will move the code to appropriate commits, but this way is easier for you to review.

I will handle context and etag in the follow-up PRs.

@saledjenic saledjenic force-pushed the feat/add-auto-refresh-option-to-settings branch from fc68b55 to 106d96e Compare March 14, 2025 11:25
@saledjenic saledjenic force-pushed the auto-refresh-token-list branch from 77acac4 to 056ebaf Compare March 14, 2025 12:30
@friofry
Copy link
Contributor

friofry commented Mar 14, 2025

@friofry thanks for the review and good comments. The last commit is about the changes you proposed. Once you agree I will move the code to appropriate commits, but this way is easier for you to review.

I will handle context and etag in the follow-up PRs.

Sounds like a good plan to make these changes as a separate PR.

@friofry friofry self-requested a review March 14, 2025 12:46
Copy link
Contributor

@friofry friofry 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 to me, please add me as a reviewer for the follow-up PRs on the context and etag

Copy link

codecov bot commented Mar 14, 2025

Codecov Report

Attention: Patch coverage is 59.94475% with 145 lines in your changes missing coverage. Please review.

Project coverage is 60.62%. Comparing base (106d96e) to head (bce20bd).

Files with missing lines Patch % Lines
...token/token-lists/default-lists/downloader/main.go 0.00% 48 Missing ⚠️
services/wallet/token/token.go 38.70% 15 Missing and 4 partials ⚠️
services/wallet/token/token-lists/analyzer/main.go 0.00% 18 Missing ⚠️
services/wallet/token/token-lists/refresher.go 54.28% 10 Missing and 6 partials ⚠️
services/wallet/token/token-lists/token_lists.go 85.71% 6 Missing and 4 partials ⚠️
...rvices/wallet/token/token-lists/fetcher/fetcher.go 80.55% 3 Missing and 4 partials ⚠️
...t/token/token-lists/fetcher/fetcher_test_helper.go 71.42% 3 Missing and 3 partials ⚠️
...t/token/token-lists/fetcher/token_lists_fetcher.go 53.84% 4 Missing and 2 partials ⚠️
services/wallet/token/token-lists/builder.go 79.16% 3 Missing and 2 partials ⚠️
services/wallet/token/token-lists/fetcher/db.go 84.61% 2 Missing and 2 partials ⚠️
... and 2 more
Additional details and impacted files
@@                             Coverage Diff                              @@
##           feat/add-auto-refresh-option-to-settings    #6399      +/-   ##
============================================================================
- Coverage                                     61.03%   60.62%   -0.42%     
============================================================================
  Files                                           843      850       +7     
  Lines                                        108250   107329     -921     
============================================================================
- Hits                                          66075    65067    -1008     
- Misses                                        34545    34582      +37     
- Partials                                       7630     7680      +50     
Flag Coverage Δ
functional 23.16% <27.02%> (-0.82%) ⬇️
unit 58.82% <59.94%> (-0.43%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
services/wallet/token/token_peg.go 100.00% <100.00%> (ø)
signal/events_wallet.go 100.00% <ø> (ø)
...t/token/token-lists/fetcher/remote_list_fetcher.go 89.47% <89.47%> (ø)
services/wallet/token/token-lists/fetcher/db.go 84.61% <84.61%> (ø)
...ervices/wallet/token/token-lists/fetcher/helper.go 78.94% <78.94%> (ø)
services/wallet/token/token-lists/builder.go 79.16% <79.16%> (ø)
...t/token/token-lists/fetcher/fetcher_test_helper.go 71.42% <71.42%> (ø)
...t/token/token-lists/fetcher/token_lists_fetcher.go 53.84% <53.84%> (ø)
...rvices/wallet/token/token-lists/fetcher/fetcher.go 80.55% <80.55%> (ø)
services/wallet/token/token-lists/token_lists.go 85.71% <85.71%> (ø)
... and 4 more

... and 33 files with indirect coverage changes

downloader and analyzer moved to more appropriate location and accordingly updated to the changes made before.

`make download-tokens` should be used to update initial tokens lists for the app.

`make analyze-token-stores` should be used to analyze initial tokens lists.
Old token stores are not needed anymore since the tokens lists
are being fetched dynamically and maintained differently.
@saledjenic saledjenic force-pushed the auto-refresh-token-list branch from 056ebaf to bce20bd Compare March 14, 2025 13:44
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.

3 participants