Skip to content

Commit 30aea2d

Browse files
committed
fix(curated): stop loading curated communities as soon as you get a single valid community
Part of status-im/status-app#21514 Curated community discovery only needs one valid description to populate the UI, but it reused the general `FetchCommunity` freshness rule, which continued paging unless the stored description clock became newer than the clock captured when the request started. Allow curated requests to stop as soon as any accepted description is available, and retain an ephemeral description filter so subsequent updates arrive live without including the topic in historic synchronization sweeps.
1 parent 1bc3668 commit 30aea2d

5 files changed

Lines changed: 101 additions & 10 deletions

protocol/messenger_curated_communities.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package protocol
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"reflect"
78
"time"
89

@@ -12,6 +13,7 @@ import (
1213

1314
gocommon "github.com/status-im/status-go/common"
1415
"github.com/status-im/status-go/internal/crypto/types"
16+
types2 "github.com/status-im/status-go/pkg/messaging/types"
1517
"github.com/status-im/status-go/protocol/communities"
1618
"github.com/status-im/status-go/services/wallet/common"
1719
)
@@ -142,6 +144,10 @@ func (m *Messenger) getCuratedCommunitiesFromContract() (*communities.CuratedCom
142144
}
143145

144146
func (m *Messenger) fetchCuratedCommunities(curatedCommunities *communities.CuratedCommunities) (*communities.KnownCommunitiesResponse, error) {
147+
if err := m.subscribeToCuratedCommunityDescriptions(curatedCommunities.ContractCommunities); err != nil {
148+
return nil, err
149+
}
150+
145151
response, err := m.communitiesManager.GetStoredDescriptionForCommunities(curatedCommunities.ContractCommunities)
146152
if err != nil {
147153
return nil, err
@@ -156,7 +162,10 @@ func (m *Messenger) fetchCuratedCommunities(curatedCommunities *communities.Cura
156162
m.logger.Debug("fetching unknown curated communities")
157163

158164
for _, communityID := range response.UnknownCommunities {
159-
_, _, err := m.storeNodeRequestsManager.FetchCommunity(m.ctx, communityID, nil)
165+
options := []StoreNodeRequestOption{
166+
WithRequireNewerCommunityDescription(false),
167+
}
168+
_, _, err := m.storeNodeRequestsManager.FetchCommunity(m.ctx, communityID, options)
160169
if err != nil {
161170
m.logger.Error("failed to fetch curated community",
162171
zap.String("communityID", communityID),
@@ -169,6 +178,19 @@ func (m *Messenger) fetchCuratedCommunities(curatedCommunities *communities.Cura
169178
return response, nil
170179
}
171180

181+
func (m *Messenger) subscribeToCuratedCommunityDescriptions(communityIDs []string) error {
182+
for _, communityID := range communityIDs {
183+
filter, created, err := m.storeNodeRequestsManager.getFilter(storeNodeCommunityRequest, communityID, types2.DefaultShard())
184+
if err != nil {
185+
if created && filter != nil {
186+
m.storeNodeRequestsManager.forgetFilter(filter)
187+
}
188+
return fmt.Errorf("failed to subscribe to curated community %s: %w", communityID, err)
189+
}
190+
}
191+
return nil
192+
}
193+
172194
func (m *Messenger) CuratedCommunities() (*communities.KnownCommunitiesResponse, error) {
173195
curatedCommunities, err := m.communitiesManager.GetCuratedCommunities()
174196
if err != nil {

protocol/messenger_curated_communities_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import (
66
"github.com/stretchr/testify/require"
77

88
"github.com/status-im/status-go/internal/connection"
9+
"github.com/status-im/status-go/internal/crypto"
10+
cryptotypes "github.com/status-im/status-go/internal/crypto/types"
11+
"github.com/status-im/status-go/pkg/messaging"
12+
types2 "github.com/status-im/status-go/pkg/messaging/types"
913
)
1014

1115
func TestShouldPauseCuratedCommunitiesUpdateLoop(t *testing.T) {
@@ -16,3 +20,34 @@ func TestShouldPauseCuratedCommunitiesUpdateLoop(t *testing.T) {
1620
m.setConnectionState(connection.State{Expensive: true})
1721
require.True(t, m.shouldPauseCuratedCommunitiesUpdateLoop())
1822
}
23+
24+
func TestSubscribeToCuratedCommunityDescriptions(t *testing.T) {
25+
messagingEnv, err := messaging.NewTestMessagingEnvironment()
26+
require.NoError(t, err)
27+
require.NoError(t, messagingEnv.Setup(t))
28+
29+
m, err := newTestMessenger(t, messagingEnv, testMessengerConfig{})
30+
require.NoError(t, err)
31+
32+
newCommunityKey, err := crypto.GenerateKey()
33+
require.NoError(t, err)
34+
newCommunityID := cryptotypes.HexBytes(crypto.CompressPubkey(&newCommunityKey.PublicKey)).String()
35+
36+
existingCommunityKey, err := crypto.GenerateKey()
37+
require.NoError(t, err)
38+
existingCommunityID := cryptotypes.HexBytes(crypto.CompressPubkey(&existingCommunityKey.PublicKey)).String()
39+
existingFilters, err := m.messaging.InitPublicChats(types2.ChatsToInitialize{{
40+
ChatID: existingCommunityID,
41+
PubsubTopic: types2.DefaultShard().PubsubTopic(),
42+
}})
43+
require.NoError(t, err)
44+
require.Len(t, existingFilters, 1)
45+
require.False(t, existingFilters[0].IsEphemeral())
46+
47+
require.NoError(t, m.subscribeToCuratedCommunityDescriptions([]string{newCommunityID, existingCommunityID}))
48+
49+
newFilter := m.messaging.ChatFilterByChatID(newCommunityID)
50+
require.NotNil(t, newFilter)
51+
require.True(t, newFilter.IsEphemeral())
52+
require.False(t, m.messaging.ChatFilterByChatID(existingCommunityID).IsEphemeral())
53+
}

protocol/messenger_store_node_request_manager.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,10 @@ func (r *storeNodeRequest) finalize() {
329329
}
330330
}
331331

332+
func (r *storeNodeRequest) hasFoundCommunityDescription(clock uint64) bool {
333+
return !r.config.RequireNewerCommunityDescription || clock > r.minimumDataClock
334+
}
335+
332336
func (r *storeNodeRequest) shouldFetchNextPage(envelopesCount int) (bool, uint64) {
333337
logger := r.manager.logger.With(
334338
zap.Any("requestID", r.requestID),
@@ -393,7 +397,7 @@ func (r *storeNodeRequest) shouldFetchNextPage(envelopesCount int) (bool, uint64
393397
// Would be perfect if we could track that the community was in these particular envelopes,
394398
// but I don't think that's possible right now. We check if clock was updated instead.
395399

396-
if community.Clock() <= r.minimumDataClock {
400+
if !r.hasFoundCommunityDescription(community.Clock()) {
397401
logger.Debug("local community description is not newer than existing",
398402
zap.Any("existingClock", community.Clock()),
399403
zap.Any("minimumDataClock", r.minimumDataClock),

protocol/messenger_store_node_request_manager_config.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
package protocol
22

33
type StoreNodeRequestConfig struct {
4-
WaitForResponse bool
5-
StopWhenDataFound bool
6-
InitialPageSize uint64
7-
FurtherPageSize uint64
4+
WaitForResponse bool
5+
StopWhenDataFound bool
6+
RequireNewerCommunityDescription bool
7+
InitialPageSize uint64
8+
FurtherPageSize uint64
89
}
910

1011
type StoreNodeRequestOption func(*StoreNodeRequestConfig)
1112

1213
func defaultStoreNodeRequestConfig() StoreNodeRequestConfig {
1314
return StoreNodeRequestConfig{
14-
WaitForResponse: true,
15-
StopWhenDataFound: true,
16-
InitialPageSize: initialStoreNodeRequestPageSize,
17-
FurtherPageSize: defaultStoreNodeRequestPageSize,
15+
WaitForResponse: true,
16+
StopWhenDataFound: true,
17+
RequireNewerCommunityDescription: true,
18+
InitialPageSize: initialStoreNodeRequestPageSize,
19+
FurtherPageSize: defaultStoreNodeRequestPageSize,
1820
}
1921
}
2022

@@ -40,6 +42,12 @@ func WithStopWhenDataFound(stopWhenDataFound bool) StoreNodeRequestOption {
4042
}
4143
}
4244

45+
func WithRequireNewerCommunityDescription(requireNewer bool) StoreNodeRequestOption {
46+
return func(c *StoreNodeRequestConfig) {
47+
c.RequireNewerCommunityDescription = requireNewer
48+
}
49+
}
50+
4351
func WithInitialPageSize(initialPageSize uint64) StoreNodeRequestOption {
4452
return func(c *StoreNodeRequestConfig) {
4553
c.InitialPageSize = initialPageSize
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package protocol
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestStoreNodeRequestCommunityDescriptionFreshness(t *testing.T) {
10+
request := &storeNodeRequest{
11+
minimumDataClock: 10,
12+
config: defaultStoreNodeRequestConfig(),
13+
}
14+
15+
require.False(t, request.hasFoundCommunityDescription(10))
16+
require.True(t, request.hasFoundCommunityDescription(11))
17+
18+
request.config = buildStoreNodeRequestConfig([]StoreNodeRequestOption{
19+
WithRequireNewerCommunityDescription(false),
20+
})
21+
require.True(t, request.hasFoundCommunityDescription(10))
22+
}

0 commit comments

Comments
 (0)