diff --git a/services/ext/service.go b/services/ext/service.go index d04e3b568..a8a658128 100644 --- a/services/ext/service.go +++ b/services/ext/service.go @@ -39,7 +39,6 @@ import ( "github.com/status-im/status-go/protocol" "github.com/status-im/status-go/protocol/anonmetrics" "github.com/status-im/status-go/protocol/common" - "github.com/status-im/status-go/protocol/common/shard" "github.com/status-im/status-go/protocol/communities" "github.com/status-im/status-go/protocol/communities/token" "github.com/status-im/status-go/protocol/protobuf" @@ -550,18 +549,14 @@ func (s *Service) FillCollectibleMetadata(collectible *thirdparty.FullCollectibl return fmt.Errorf("invalid communityID") } - // FetchCommunityInfo should have been previously called once to ensure - // that the latest version of the CommunityDescription is available in the DB - community, err := s.fetchCommunity(communityID, false) - + community, err := s.messenger.FindCommunityInfoFromDB(communityID) if err != nil { + if err == communities.ErrOrgNotFound { + return nil + } return err } - if community == nil { - return nil - } - tokenMetadata, err := s.fetchCommunityCollectibleMetadata(community, id.ContractID) if err != nil { @@ -637,48 +632,81 @@ func communityToInfo(community *communities.Community) *thirdparty.CommunityInfo } } -func (s *Service) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) { - community, err := s.fetchCommunity(communityID, true) +func (s *Service) fetchCommunityFromStoreNodes(communityID string) (*thirdparty.CommunityInfo, error) { + community, err := s.messenger.FetchCommunity(&protocol.FetchCommunityRequest{ + CommunityKey: communityID, + TryDatabase: false, + WaitForResponse: true, + }) if err != nil { return nil, err } + return communityToInfo(community), nil +} + +// Fetch latest community from store nodes. +func (s *Service) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) { + if s.messenger == nil { + return nil, fmt.Errorf("messenger not ready") + } + + community, err := s.messenger.FindCommunityInfoFromDB(communityID) + if err != nil && err != communities.ErrOrgNotFound { + return nil, err + } + + // Fetch latest version from store nodes + if community == nil || !community.IsControlNode() { + return s.fetchCommunityFromStoreNodes(communityID) + } return communityToInfo(community), nil } -func (s *Service) fetchCommunity(communityID string, fetchLatest bool) (*communities.Community, error) { +// Fetch latest community from store nodes only if any collectibles data is missing. +func (s *Service) FetchCommunityInfoForCollectibles(communityID string, ids []thirdparty.CollectibleUniqueID) (*thirdparty.CommunityInfo, error) { if s.messenger == nil { return nil, fmt.Errorf("messenger not ready") } - // Try to fetch metadata from Messenger communities - - // TODO: we need the shard information in the collectible to be able to retrieve info for - // communities that have specific shards - - if fetchLatest { - // Try to fetch the latest version of the Community - var shard *shard.Shard = nil // TODO: build this with info from token - // NOTE: The community returned by this function will be nil if - // the version we have in the DB is the latest available. - _, err := s.messenger.FetchCommunity(&protocol.FetchCommunityRequest{ - CommunityKey: communityID, - Shard: shard, - TryDatabase: false, - WaitForResponse: true, - }) - if err != nil { - return nil, err - } - } - - // Get the latest successfully fetched version of the Community community, err := s.messenger.FindCommunityInfoFromDB(communityID) - if err != nil { + if err != nil && err != communities.ErrOrgNotFound { return nil, err } - return community, nil + if community == nil { + return s.fetchCommunityFromStoreNodes(communityID) + } + + if community.IsControlNode() { + return communityToInfo(community), nil + } + + contractIDs := func() map[string]thirdparty.ContractID { + result := map[string]thirdparty.ContractID{} + for _, id := range ids { + result[id.HashKey()] = id.ContractID + } + return result + }() + + hasAllMetadata := true + for _, contractID := range contractIDs { + tokenMetadata, err := s.fetchCommunityCollectibleMetadata(community, contractID) + if err != nil { + return nil, err + } + if tokenMetadata == nil { + hasAllMetadata = false + break + } + } + + if !hasAllMetadata { + return s.fetchCommunityFromStoreNodes(communityID) + } + + return communityToInfo(community), nil } func (s *Service) fetchCommunityToken(communityID string, contractID thirdparty.ContractID) (*token.CommunityToken, error) { diff --git a/services/wallet/collectibles/manager.go b/services/wallet/collectibles/manager.go index c67e8deec..5f5817284 100644 --- a/services/wallet/collectibles/manager.go +++ b/services/wallet/collectibles/manager.go @@ -728,7 +728,7 @@ func (o *Manager) fillCommunityID(asset *thirdparty.FullCollectibleData) error { } func (o *Manager) fetchCommunityAssets(communityID string, communityAssets []*thirdparty.FullCollectibleData) error { - communityInfo, err := o.communityManager.FetchCommunityInfo(communityID) + communityInfo, err := o.communityManager.FetchCommunityInfoForCollectibles(communityID, idsFromAssets(communityAssets)) // If the community is found, we update the DB. // If the community is not found, we only insert new entries to the DB (don't replace what is already there). diff --git a/services/wallet/collectibles/types.go b/services/wallet/collectibles/types.go index d3daf5d13..583c8e751 100644 --- a/services/wallet/collectibles/types.go +++ b/services/wallet/collectibles/types.go @@ -204,3 +204,11 @@ func communityInfoToData(communityID string, community *thirdparty.CommunityInfo return ret } + +func idsFromAssets(assets []*thirdparty.FullCollectibleData) []thirdparty.CollectibleUniqueID { + result := make([]thirdparty.CollectibleUniqueID, len(assets)) + for i, asset := range assets { + result[i] = asset.CollectibleData.ID + } + return result +} diff --git a/services/wallet/community/manager.go b/services/wallet/community/manager.go index 58afcede6..f5e5ea9c8 100644 --- a/services/wallet/community/manager.go +++ b/services/wallet/community/manager.go @@ -66,8 +66,8 @@ func (cm *Manager) setCommunityInfo(id string, c *thirdparty.CommunityInfo) (err return cm.db.SetCommunityInfo(id, c) } -func (cm *Manager) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) { - communityInfo, err := cm.communityInfoProvider.FetchCommunityInfo(communityID) +func (cm *Manager) fetchCommunityInfo(communityID string, fetcher func() (*thirdparty.CommunityInfo, error)) (*thirdparty.CommunityInfo, error) { + communityInfo, err := fetcher() if err != nil { dbErr := cm.setCommunityInfo(communityID, nil) if dbErr != nil { @@ -79,6 +79,18 @@ func (cm *Manager) FetchCommunityInfo(communityID string) (*thirdparty.Community return communityInfo, err } +func (cm *Manager) FetchCommunityInfo(communityID string) (*thirdparty.CommunityInfo, error) { + return cm.fetchCommunityInfo(communityID, func() (*thirdparty.CommunityInfo, error) { + return cm.communityInfoProvider.FetchCommunityInfo(communityID) + }) +} + +func (cm *Manager) FetchCommunityInfoForCollectibles(communityID string, ids []thirdparty.CollectibleUniqueID) (*thirdparty.CommunityInfo, error) { + return cm.fetchCommunityInfo(communityID, func() (*thirdparty.CommunityInfo, error) { + return cm.communityInfoProvider.FetchCommunityInfoForCollectibles(communityID, ids) + }) +} + func (cm *Manager) FetchCommunityMetadataAsync(communityID string) { go func() { communityInfo, err := cm.FetchCommunityMetadata(communityID) diff --git a/services/wallet/thirdparty/community_types.go b/services/wallet/thirdparty/community_types.go index 3c065aad3..c97ef276f 100644 --- a/services/wallet/thirdparty/community_types.go +++ b/services/wallet/thirdparty/community_types.go @@ -14,4 +14,5 @@ type CommunityInfoProvider interface { // Collectible-related methods GetCommunityID(tokenURI string) string FillCollectibleMetadata(collectible *FullCollectibleData) error + FetchCommunityInfoForCollectibles(communityID string, ids []CollectibleUniqueID) (*CommunityInfo, error) }