chore(community)_: reevaluateMembers optimization (#5169)
* chore(community)_: reevaluateMembers optinizations
This commit is contained in:
parent
948e09af03
commit
77541725aa
|
@ -2186,6 +2186,14 @@ func (o *Community) AddMemberToChat(chatID string, publicKey *ecdsa.PublicKey,
|
|||
return changes, nil
|
||||
}
|
||||
|
||||
func (o *Community) PopulateChannelsWithAllMembers() {
|
||||
members := o.Members()
|
||||
for _, channel := range o.Chats() {
|
||||
channel.Members = members
|
||||
}
|
||||
o.increaseClock()
|
||||
}
|
||||
|
||||
func (o *Community) PopulateChatWithAllMembers(chatID string) (*CommunityChanges, error) {
|
||||
o.mutex.Lock()
|
||||
defer o.mutex.Unlock()
|
||||
|
@ -2479,6 +2487,7 @@ func (o *Community) deleteTokenPermission(permissionID string) (*CommunityChange
|
|||
changes := o.emptyCommunityChanges()
|
||||
|
||||
changes.TokenPermissionsRemoved[permissionID] = NewCommunityTokenPermission(permission)
|
||||
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -991,6 +991,11 @@ func (m *Manager) EditCommunityTokenPermission(request *requests.EditCommunityTo
|
|||
return community, changes, nil
|
||||
}
|
||||
|
||||
// use it only for testing purposes
|
||||
func (m *Manager) ReevaluateMembers(communityID types.HexBytes) (*Community, map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey, error) {
|
||||
return m.reevaluateMembers(communityID)
|
||||
}
|
||||
|
||||
func (m *Manager) reevaluateMembers(communityID types.HexBytes) (*Community, map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey, error) {
|
||||
m.communityLock.Lock(communityID)
|
||||
defer m.communityLock.Unlock(communityID)
|
||||
|
@ -1006,16 +1011,23 @@ func (m *Manager) reevaluateMembers(communityID types.HexBytes) (*Community, map
|
|||
return nil, nil, ErrNotEnoughPermissions
|
||||
}
|
||||
|
||||
becomeMemberPermissions := community.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_MEMBER)
|
||||
becomeAdminPermissions := community.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
||||
becomeTokenMasterPermissions := community.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER)
|
||||
communityPermissionsPreParsedData, channelPermissionsPreParsedData := PreParsePermissionsData(community.tokenPermissions())
|
||||
|
||||
hasMemberPermissions := len(becomeMemberPermissions) > 0
|
||||
hasMemberPermissions := communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_MEMBER] != nil
|
||||
|
||||
if len(channelPermissionsPreParsedData) == 0 {
|
||||
community.PopulateChannelsWithAllMembers()
|
||||
}
|
||||
|
||||
newPrivilegedRoles := make(map[protobuf.CommunityMember_Roles][]*ecdsa.PublicKey)
|
||||
newPrivilegedRoles[protobuf.CommunityMember_ROLE_TOKEN_MASTER] = []*ecdsa.PublicKey{}
|
||||
newPrivilegedRoles[protobuf.CommunityMember_ROLE_ADMIN] = []*ecdsa.PublicKey{}
|
||||
|
||||
membersAccounts, err := m.persistence.GetCommunityRequestsToJoinRevealedAddresses(community.ID())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for memberKey := range community.Members() {
|
||||
memberPubKey, err := common.HexToPubkey(memberKey)
|
||||
if err != nil {
|
||||
|
@ -1028,13 +1040,9 @@ func (m *Manager) reevaluateMembers(communityID types.HexBytes) (*Community, map
|
|||
|
||||
isCurrentRoleTokenMaster := community.IsMemberTokenMaster(memberPubKey)
|
||||
isCurrentRoleAdmin := community.IsMemberAdmin(memberPubKey)
|
||||
requestID := CalculateRequestID(memberKey, community.ID())
|
||||
revealedAccounts, err := m.persistence.GetRequestToJoinRevealedAddresses(requestID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
memberHasWallet := len(revealedAccounts) > 0
|
||||
revealedAccount, exists := membersAccounts[memberKey]
|
||||
memberHasWallet := exists
|
||||
|
||||
// Check if user has privilege role without sharing the account to controlNode
|
||||
// or user treated as a member without wallet in closed community
|
||||
|
@ -1046,9 +1054,13 @@ func (m *Manager) reevaluateMembers(communityID types.HexBytes) (*Community, map
|
|||
continue
|
||||
}
|
||||
|
||||
accountsAndChainIDs := revealedAccountsToAccountsAndChainIDsCombination(revealedAccounts)
|
||||
accountsAndChainIDs := revealedAccountsToAccountsAndChainIDsCombination(revealedAccount)
|
||||
|
||||
isNewRoleTokenMaster, err := m.ReevaluatePrivilegedMember(community, becomeTokenMasterPermissions, accountsAndChainIDs, memberPubKey,
|
||||
isNewRoleTokenMaster, err := m.ReevaluatePrivilegedMember(
|
||||
community,
|
||||
communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER],
|
||||
accountsAndChainIDs,
|
||||
memberPubKey,
|
||||
protobuf.CommunityMember_ROLE_TOKEN_MASTER, isCurrentRoleTokenMaster)
|
||||
|
||||
if err != nil {
|
||||
|
@ -1064,7 +1076,11 @@ func (m *Manager) reevaluateMembers(communityID types.HexBytes) (*Community, map
|
|||
continue
|
||||
}
|
||||
|
||||
isNewRoleAdmin, err := m.ReevaluatePrivilegedMember(community, becomeAdminPermissions, accountsAndChainIDs, memberPubKey,
|
||||
isNewRoleAdmin, err := m.ReevaluatePrivilegedMember(
|
||||
community,
|
||||
communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_ADMIN],
|
||||
accountsAndChainIDs,
|
||||
memberPubKey,
|
||||
protobuf.CommunityMember_ROLE_ADMIN, isCurrentRoleAdmin)
|
||||
|
||||
if err != nil {
|
||||
|
@ -1081,7 +1097,10 @@ func (m *Manager) reevaluateMembers(communityID types.HexBytes) (*Community, map
|
|||
}
|
||||
|
||||
if hasMemberPermissions {
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(becomeMemberPermissions, accountsAndChainIDs, true)
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(
|
||||
communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_MEMBER],
|
||||
accountsAndChainIDs,
|
||||
true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -1096,52 +1115,96 @@ func (m *Manager) reevaluateMembers(communityID types.HexBytes) (*Community, map
|
|||
}
|
||||
}
|
||||
|
||||
// Validate channel permissions
|
||||
for channelID := range community.Chats() {
|
||||
chatID := community.ChatID(channelID)
|
||||
|
||||
viewOnlyPermissions := community.ChannelTokenPermissionsByType(chatID, protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL)
|
||||
viewAndPostPermissions := community.ChannelTokenPermissionsByType(chatID, protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL)
|
||||
|
||||
if len(viewOnlyPermissions) == 0 && len(viewAndPostPermissions) == 0 {
|
||||
// ensure all members are added back if channel permissions were removed
|
||||
_, err = community.PopulateChatWithAllMembers(channelID)
|
||||
err = m.reevaluateMemberChannelsPermissions(community, memberPubKey, channelPermissionsPreParsedData, accountsAndChainIDs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
response, err := m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountsAndChainIDs, true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
isMemberAlreadyInChannel := community.IsMemberInChat(memberPubKey, channelID)
|
||||
|
||||
if response.ViewOnlyPermissions.Satisfied || response.ViewAndPostPermissions.Satisfied {
|
||||
channelRole := protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
|
||||
if response.ViewAndPostPermissions.Satisfied {
|
||||
channelRole = protobuf.CommunityMember_CHANNEL_ROLE_POSTER
|
||||
}
|
||||
|
||||
// Add the member back to the chat member list in case the role changed (it replaces the previous values)
|
||||
_, err := community.AddMemberToChat(channelID, memberPubKey, []protobuf.CommunityMember_Roles{}, channelRole)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
} else if isMemberAlreadyInChannel {
|
||||
_, err := community.RemoveUserFromChat(memberPubKey, channelID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return community, newPrivilegedRoles, m.saveAndPublish(community)
|
||||
}
|
||||
|
||||
func (m *Manager) reevaluateMemberChannelsPermissions(community *Community, memberPubKey *ecdsa.PublicKey,
|
||||
channelPermissionsPreParsedData map[string]*PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination) error {
|
||||
|
||||
if len(channelPermissionsPreParsedData) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check which permissions we satisfy and which not
|
||||
channelPermissionsCheckResult, err := m.checkChannelsPermissions(channelPermissionsPreParsedData, accountsAndChainIDs, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for channelID := range community.Chats() {
|
||||
chatID := community.ChatID(channelID)
|
||||
isMemberAlreadyInChannel := community.IsMemberInChat(memberPubKey, channelID)
|
||||
|
||||
channelPermissionsCheckResult, exists := channelPermissionsCheckResult[chatID]
|
||||
|
||||
// if channel permissions were removed member must be added back
|
||||
if !exists {
|
||||
if !isMemberAlreadyInChannel {
|
||||
_, err := community.AddMemberToChat(channelID, memberPubKey, []protobuf.CommunityMember_Roles{}, protobuf.CommunityMember_CHANNEL_ROLE_POSTER)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
viewAndPostSatisfied, viewAndPosPermissionExists := channelPermissionsCheckResult[protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL]
|
||||
viewOnlySatisfied, viewOnlyPermissionExists := channelPermissionsCheckResult[protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL]
|
||||
|
||||
satisfied := false
|
||||
channelRole := protobuf.CommunityMember_CHANNEL_ROLE_VIEWER
|
||||
if viewAndPosPermissionExists && viewAndPostSatisfied {
|
||||
satisfied = viewAndPostSatisfied
|
||||
channelRole = protobuf.CommunityMember_CHANNEL_ROLE_POSTER
|
||||
} else if !satisfied && viewOnlyPermissionExists {
|
||||
satisfied = viewOnlySatisfied
|
||||
}
|
||||
|
||||
if satisfied {
|
||||
// Add the member back to the chat member list in case the role changed (it replaces the previous values)
|
||||
_, err := community.AddMemberToChat(channelID, memberPubKey, []protobuf.CommunityMember_Roles{}, channelRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if !satisfied && isMemberAlreadyInChannel {
|
||||
_, err := community.RemoveUserFromChat(memberPubKey, channelID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) checkChannelsPermissions(channelsPermissionsPreParsedData map[string]*PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (map[string]map[protobuf.CommunityTokenPermission_Type]bool, error) {
|
||||
channelPermissionsCheckResult := make(map[string]map[protobuf.CommunityTokenPermission_Type]bool)
|
||||
for _, channelsPermissionPreParsedData := range channelsPermissionsPreParsedData {
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(channelsPermissionPreParsedData, accountsAndChainIDs, true)
|
||||
if err != nil {
|
||||
return channelPermissionsCheckResult, err
|
||||
}
|
||||
// Note: in `PreParsedCommunityPermissionsData` for channels there will be only one permission
|
||||
// no need to iterate over `Permissions`
|
||||
for _, chatId := range channelsPermissionPreParsedData.Permissions[0].ChatIds {
|
||||
if _, exists := channelPermissionsCheckResult[chatId]; !exists {
|
||||
channelPermissionsCheckResult[chatId] = make(map[protobuf.CommunityTokenPermission_Type]bool)
|
||||
}
|
||||
satisfied, exists := channelPermissionsCheckResult[chatId][channelsPermissionPreParsedData.Permissions[0].Type]
|
||||
if exists && satisfied {
|
||||
continue
|
||||
}
|
||||
channelPermissionsCheckResult[chatId][channelsPermissionPreParsedData.Permissions[0].Type] = permissionResponse.Satisfied
|
||||
}
|
||||
}
|
||||
return channelPermissionsCheckResult, nil
|
||||
}
|
||||
|
||||
func (m *Manager) StartMembersReevaluationLoop(communityID types.HexBytes, reevaluateOnStart bool) {
|
||||
go m.reevaluateMembersLoop(communityID, reevaluateOnStart)
|
||||
}
|
||||
|
@ -2462,24 +2525,22 @@ func (m *Manager) CheckPermissionToJoin(id []byte, addresses []gethcommon.Addres
|
|||
}
|
||||
|
||||
return m.PermissionChecker.CheckPermissionToJoin(community, addresses)
|
||||
|
||||
}
|
||||
|
||||
func (m *Manager) accountsSatisfyPermissionsToJoin(community *Community, accounts []*protobuf.RevealedAccount) (bool, protobuf.CommunityMember_Roles, error) {
|
||||
accountsAndChainIDs := revealedAccountsToAccountsAndChainIDsCombination(accounts)
|
||||
becomeAdminPermissions := community.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
||||
becomeMemberPermissions := community.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_MEMBER)
|
||||
becomeTokenMasterPermissions := community.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER)
|
||||
func (m *Manager) accountsSatisfyPermissionsToJoin(
|
||||
communityPermissionsPreParsedData map[protobuf.CommunityTokenPermission_Type]*PreParsedCommunityPermissionsData,
|
||||
accountsAndChainIDs []*AccountChainIDsCombination) (bool, protobuf.CommunityMember_Roles, error) {
|
||||
|
||||
if m.accountsHasPrivilegedPermission(becomeTokenMasterPermissions, accountsAndChainIDs) {
|
||||
if m.accountsHasPrivilegedPermission(communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER], accountsAndChainIDs) {
|
||||
return true, protobuf.CommunityMember_ROLE_TOKEN_MASTER, nil
|
||||
}
|
||||
if m.accountsHasPrivilegedPermission(becomeAdminPermissions, accountsAndChainIDs) {
|
||||
if m.accountsHasPrivilegedPermission(communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_ADMIN], accountsAndChainIDs) {
|
||||
return true, protobuf.CommunityMember_ROLE_ADMIN, nil
|
||||
}
|
||||
|
||||
if len(becomeMemberPermissions) > 0 {
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(becomeMemberPermissions, accountsAndChainIDs, true)
|
||||
preParsedBecomeMemberPermissions := communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_MEMBER]
|
||||
if preParsedBecomeMemberPermissions != nil {
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(preParsedBecomeMemberPermissions, accountsAndChainIDs, true)
|
||||
if err != nil {
|
||||
return false, protobuf.CommunityMember_ROLE_NONE, err
|
||||
}
|
||||
|
@ -2490,37 +2551,49 @@ func (m *Manager) accountsSatisfyPermissionsToJoin(community *Community, account
|
|||
return true, protobuf.CommunityMember_ROLE_NONE, nil
|
||||
}
|
||||
|
||||
func (m *Manager) accountsSatisfyPermissionsToJoinChannels(community *Community, accounts []*protobuf.RevealedAccount) (map[string]*protobuf.CommunityChat, map[string]*protobuf.CommunityChat, error) {
|
||||
func (m *Manager) accountsSatisfyPermissionsToJoinChannels(
|
||||
community *Community,
|
||||
channelPermissionsPreParsedData map[string]*PreParsedCommunityPermissionsData,
|
||||
accountsAndChainIDs []*AccountChainIDsCombination) (map[string]*protobuf.CommunityChat, map[string]*protobuf.CommunityChat, error) {
|
||||
|
||||
viewChats := make(map[string]*protobuf.CommunityChat)
|
||||
viewAndPostChats := make(map[string]*protobuf.CommunityChat)
|
||||
|
||||
accountsAndChainIDs := revealedAccountsToAccountsAndChainIDsCombination(accounts)
|
||||
if len(channelPermissionsPreParsedData) == 0 {
|
||||
for channelID, channel := range community.config.CommunityDescription.Chats {
|
||||
viewAndPostChats[channelID] = channel
|
||||
}
|
||||
|
||||
return viewChats, viewAndPostChats, nil
|
||||
}
|
||||
|
||||
// check which permissions we satisfy and which not
|
||||
channelPermissionsCheckResult, err := m.checkChannelsPermissions(channelPermissionsPreParsedData, accountsAndChainIDs, true)
|
||||
if err != nil {
|
||||
m.logger.Warn("check channel permission failed: %v", zap.Error(err))
|
||||
return viewChats, viewAndPostChats, err
|
||||
}
|
||||
|
||||
for channelID, channel := range community.config.CommunityDescription.Chats {
|
||||
channelViewOnlyPermissions := community.ChannelTokenPermissionsByType(community.IDString()+channelID, protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL)
|
||||
channelViewAndPostPermissions := community.ChannelTokenPermissionsByType(community.IDString()+channelID, protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL)
|
||||
channelPermissions := append(channelViewOnlyPermissions, channelViewAndPostPermissions...)
|
||||
chatID := community.ChatID(channelID)
|
||||
channelPermissionsCheckResult, exists := channelPermissionsCheckResult[chatID]
|
||||
|
||||
if len(channelPermissions) == 0 {
|
||||
if !exists {
|
||||
viewAndPostChats[channelID] = channel
|
||||
continue
|
||||
}
|
||||
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(channelPermissions, accountsAndChainIDs, true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
viewAndPostSatisfied, exists := channelPermissionsCheckResult[protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL]
|
||||
if exists && viewAndPostSatisfied {
|
||||
delete(viewChats, channelID)
|
||||
viewAndPostChats[channelID] = channel
|
||||
continue
|
||||
}
|
||||
|
||||
if permissionResponse.Satisfied {
|
||||
highestRole := calculateRolesAndHighestRole(permissionResponse.Permissions).HighestRole
|
||||
if highestRole == nil {
|
||||
return nil, nil, errors.New("failed to calculate highest role")
|
||||
}
|
||||
switch highestRole.Role {
|
||||
case protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL:
|
||||
viewOnlySatisfied, exists := channelPermissionsCheckResult[protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL]
|
||||
if exists && viewOnlySatisfied {
|
||||
if _, exists := viewAndPostChats[channelID]; !exists {
|
||||
viewChats[channelID] = channel
|
||||
case protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL:
|
||||
viewAndPostChats[channelID] = channel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2548,7 +2621,11 @@ func (m *Manager) AcceptRequestToJoin(dbRequest *RequestToJoin) (*Community, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
permissionsSatisfied, role, err := m.accountsSatisfyPermissionsToJoin(community, revealedAccounts)
|
||||
accountsAndChainIDs := revealedAccountsToAccountsAndChainIDsCombination(revealedAccounts)
|
||||
|
||||
communityPermissionsPreParsedData, channelPermissionsPreParsedData := PreParsePermissionsData(community.tokenPermissions())
|
||||
|
||||
permissionsSatisfied, role, err := m.accountsSatisfyPermissionsToJoin(communityPermissionsPreParsedData, accountsAndChainIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2567,7 +2644,7 @@ func (m *Manager) AcceptRequestToJoin(dbRequest *RequestToJoin) (*Community, err
|
|||
return nil, err
|
||||
}
|
||||
|
||||
viewChannels, postChannels, err := m.accountsSatisfyPermissionsToJoinChannels(community, revealedAccounts)
|
||||
viewChannels, postChannels, err := m.accountsSatisfyPermissionsToJoinChannels(community, channelPermissionsPreParsedData, accountsAndChainIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -3001,6 +3078,8 @@ func (m *Manager) CheckChannelPermissions(communityID types.HexBytes, chatID str
|
|||
|
||||
viewOnlyPermissions := community.ChannelTokenPermissionsByType(chatID, protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL)
|
||||
viewAndPostPermissions := community.ChannelTokenPermissionsByType(chatID, protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL)
|
||||
viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
|
||||
viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
|
||||
|
||||
allChainIDs, err := m.tokenManager.GetAllChainIDs()
|
||||
if err != nil {
|
||||
|
@ -3008,7 +3087,7 @@ func (m *Manager) CheckChannelPermissions(communityID types.HexBytes, chatID str
|
|||
}
|
||||
accountsAndChainIDs := combineAddressesAndChainIDs(addresses, allChainIDs)
|
||||
|
||||
response, err := m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountsAndChainIDs, false)
|
||||
response, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountsAndChainIDs, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -3035,7 +3114,7 @@ type CheckChannelViewAndPostPermissionsResult struct {
|
|||
Permissions map[string]*PermissionTokenCriteriaResult `json:"permissions"`
|
||||
}
|
||||
|
||||
func (m *Manager) checkChannelPermissions(viewOnlyPermissions []*CommunityTokenPermission, viewAndPostPermissions []*CommunityTokenPermission, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (*CheckChannelPermissionsResponse, error) {
|
||||
func (m *Manager) checkChannelPermissions(viewOnlyPreParsedPermissions *PreParsedCommunityPermissionsData, viewAndPostPreParsedPermissions *PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (*CheckChannelPermissionsResponse, error) {
|
||||
|
||||
response := &CheckChannelPermissionsResponse{
|
||||
ViewOnlyPermissions: &CheckChannelViewOnlyPermissionsResult{
|
||||
|
@ -3048,18 +3127,18 @@ func (m *Manager) checkChannelPermissions(viewOnlyPermissions []*CommunityTokenP
|
|||
},
|
||||
}
|
||||
|
||||
viewOnlyPermissionsResponse, err := m.PermissionChecker.CheckPermissions(viewOnlyPermissions, accountsAndChainIDs, shortcircuit)
|
||||
viewOnlyPermissionsResponse, err := m.PermissionChecker.CheckPermissions(viewOnlyPreParsedPermissions, accountsAndChainIDs, shortcircuit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
viewAndPostPermissionsResponse, err := m.PermissionChecker.CheckPermissions(viewAndPostPermissions, accountsAndChainIDs, shortcircuit)
|
||||
viewAndPostPermissionsResponse, err := m.PermissionChecker.CheckPermissions(viewAndPostPreParsedPermissions, accountsAndChainIDs, shortcircuit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasViewOnlyPermissions := len(viewOnlyPermissions) > 0
|
||||
hasViewAndPostPermissions := len(viewAndPostPermissions) > 0
|
||||
hasViewOnlyPermissions := viewOnlyPreParsedPermissions != nil
|
||||
hasViewAndPostPermissions := viewAndPostPreParsedPermissions != nil
|
||||
|
||||
if (hasViewAndPostPermissions && !hasViewOnlyPermissions) || (hasViewOnlyPermissions && hasViewAndPostPermissions && viewAndPostPermissionsResponse.Satisfied) {
|
||||
response.ViewOnlyPermissions.Satisfied = viewAndPostPermissionsResponse.Satisfied
|
||||
|
@ -3096,11 +3175,13 @@ func (m *Manager) CheckAllChannelsPermissions(communityID types.HexBytes, addres
|
|||
Channels: make(map[string]*CheckChannelPermissionsResponse),
|
||||
}
|
||||
|
||||
// TODO: optimize
|
||||
for channelID := range channels {
|
||||
viewOnlyPermissions := community.ChannelTokenPermissionsByType(community.IDString()+channelID, protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL)
|
||||
viewAndPostPermissions := community.ChannelTokenPermissionsByType(community.IDString()+channelID, protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL)
|
||||
|
||||
checkChannelPermissionsResponse, err := m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountsAndChainIDs, false)
|
||||
viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
|
||||
viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
|
||||
checkChannelPermissionsResponse, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountsAndChainIDs, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -4992,9 +5073,9 @@ func revealedAccountsToAccountsAndChainIDsCombination(revealedAccounts []*protob
|
|||
return accountsAndChainIDs
|
||||
}
|
||||
|
||||
func (m *Manager) accountsHasPrivilegedPermission(privilegedPermissions []*CommunityTokenPermission, accounts []*AccountChainIDsCombination) bool {
|
||||
if len(privilegedPermissions) > 0 {
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(privilegedPermissions, accounts, true)
|
||||
func (m *Manager) accountsHasPrivilegedPermission(preParsedCommunityPermissionData *PreParsedCommunityPermissionsData, accounts []*AccountChainIDsCombination) bool {
|
||||
if preParsedCommunityPermissionData != nil {
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(preParsedCommunityPermissionData, accounts, true)
|
||||
if err != nil {
|
||||
m.logger.Warn("check privileged permission failed: %v", zap.Error(err))
|
||||
return false
|
||||
|
@ -5047,16 +5128,17 @@ func (m *Manager) GetRevealedAddresses(communityID types.HexBytes, memberPk stri
|
|||
return response, err
|
||||
}
|
||||
|
||||
func (m *Manager) ReevaluatePrivilegedMember(community *Community, tokenPermissions []*CommunityTokenPermission,
|
||||
func (m *Manager) ReevaluatePrivilegedMember(community *Community, permissionsData *PreParsedCommunityPermissionsData,
|
||||
accountsAndChainIDs []*AccountChainIDsCombination, memberPubKey *ecdsa.PublicKey,
|
||||
privilegedRole protobuf.CommunityMember_Roles, alreadyHasPrivilegedRole bool) (bool, error) {
|
||||
|
||||
hasPrivilegedRolePermissions := len(tokenPermissions) > 0
|
||||
hasPrivilegedRolePermissions := permissionsData != nil
|
||||
removeCurrentRole := false
|
||||
|
||||
if hasPrivilegedRolePermissions {
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(tokenPermissions, accountsAndChainIDs, true)
|
||||
permissionResponse, err := m.PermissionChecker.CheckPermissions(permissionsData, accountsAndChainIDs, true)
|
||||
if err != nil {
|
||||
m.logger.Warn("check privileged permission failed: %v", zap.Error(err))
|
||||
return alreadyHasPrivilegedRole, err
|
||||
} else if permissionResponse.Satisfied && !alreadyHasPrivilegedRole {
|
||||
_, err = community.AddRoleToMember(memberPubKey, privilegedRole)
|
||||
|
|
|
@ -210,6 +210,8 @@ func (s *ManagerSuite) TestRetrieveTokens() {
|
|||
},
|
||||
}
|
||||
|
||||
preParsedPermissions := preParsedCommunityPermissionsData(permissions)
|
||||
|
||||
accountChainIDsCombination := []*AccountChainIDsCombination{
|
||||
&AccountChainIDsCombination{
|
||||
Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
|
||||
|
@ -218,14 +220,14 @@ func (s *ManagerSuite) TestRetrieveTokens() {
|
|||
}
|
||||
// Set response to exactly the right one
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
|
||||
resp, err := m.PermissionChecker.CheckPermissions(permissions, accountChainIDsCombination, false)
|
||||
resp, err := m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
s.Require().True(resp.Satisfied)
|
||||
|
||||
// Set response to 0
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
|
||||
resp, err = m.PermissionChecker.CheckPermissions(permissions, accountChainIDsCombination, false)
|
||||
resp, err = m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
s.Require().False(resp.Satisfied)
|
||||
|
@ -259,6 +261,8 @@ func (s *ManagerSuite) TestRetrieveCollectibles() {
|
|||
},
|
||||
}
|
||||
|
||||
preParsedPermissions := preParsedCommunityPermissionsData(permissions)
|
||||
|
||||
accountChainIDsCombination := []*AccountChainIDsCombination{
|
||||
&AccountChainIDsCombination{
|
||||
Address: gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
|
||||
|
@ -269,7 +273,7 @@ func (s *ManagerSuite) TestRetrieveCollectibles() {
|
|||
// Set response to exactly the right one
|
||||
tokenBalances = []thirdparty.TokenBalance{tokenBalance(tokenID, 1)}
|
||||
cm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), tokenBalances)
|
||||
resp, err := m.PermissionChecker.CheckPermissions(permissions, accountChainIDsCombination, false)
|
||||
resp, err := m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
s.Require().True(resp.Satisfied)
|
||||
|
@ -277,7 +281,7 @@ func (s *ManagerSuite) TestRetrieveCollectibles() {
|
|||
// Set balances to 0
|
||||
tokenBalances = []thirdparty.TokenBalance{}
|
||||
cm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), tokenBalances)
|
||||
resp, err = m.PermissionChecker.CheckPermissions(permissions, accountChainIDsCombination, false)
|
||||
resp, err = m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
s.Require().False(resp.Satisfied)
|
||||
|
@ -932,9 +936,11 @@ func (s *ManagerSuite) TestCheckChannelPermissions_NoPermissions() {
|
|||
|
||||
var viewOnlyPermissions = make([]*CommunityTokenPermission, 0)
|
||||
var viewAndPostPermissions = make([]*CommunityTokenPermission, 0)
|
||||
viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
|
||||
viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
|
||||
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountChainIDsCombination, false)
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
|
||||
|
@ -984,8 +990,11 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewOnlyPermissions() {
|
|||
|
||||
var viewAndPostPermissions = make([]*CommunityTokenPermission, 0)
|
||||
|
||||
viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
|
||||
viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
|
||||
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountChainIDsCombination, false)
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
|
||||
|
@ -996,7 +1005,7 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewOnlyPermissions() {
|
|||
|
||||
// Set response to exactly the right one
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
|
||||
resp, err = m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountChainIDsCombination, false)
|
||||
resp, err = m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
|
||||
|
@ -1044,8 +1053,11 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissions() {
|
|||
|
||||
var viewOnlyPermissions = make([]*CommunityTokenPermission, 0)
|
||||
|
||||
viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
|
||||
viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
|
||||
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountChainIDsCombination, false)
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
|
||||
|
@ -1056,7 +1068,7 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissions() {
|
|||
|
||||
// Set response to exactly the right one
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
|
||||
resp, err = m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountChainIDsCombination, false)
|
||||
resp, err = m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
|
||||
|
@ -1134,7 +1146,10 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombina
|
|||
// Set resopnse for viewAndPost permissions
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(testContractAddresses[chainID]), 0)
|
||||
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountChainIDsCombination, false)
|
||||
viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
|
||||
viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
|
||||
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
|
||||
|
@ -1213,7 +1228,10 @@ func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombina
|
|||
// Set resopnse for viewAndPost permissions
|
||||
tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(testContractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
|
||||
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPermissions, viewAndPostPermissions, accountChainIDsCombination, false)
|
||||
viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
|
||||
viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
|
||||
|
||||
resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(resp)
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
|
||||
type PermissionChecker interface {
|
||||
CheckPermissionToJoin(*Community, []gethcommon.Address) (*CheckPermissionToJoinResponse, error)
|
||||
CheckPermissions(permissions []*CommunityTokenPermission, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (*CheckPermissionsResponse, error)
|
||||
CheckPermissions(permissionsParsedData *PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (*CheckPermissionsResponse, error)
|
||||
}
|
||||
|
||||
type DefaultPermissionChecker struct {
|
||||
|
@ -33,6 +33,18 @@ type DefaultPermissionChecker struct {
|
|||
logger *zap.Logger
|
||||
}
|
||||
|
||||
type PreParsedPermissionsData struct {
|
||||
Erc721TokenRequirements map[uint64]map[string]*protobuf.TokenCriteria
|
||||
Erc20TokenAddresses []gethcommon.Address
|
||||
Erc20ChainIDsMap map[uint64]bool
|
||||
Erc721ChainIDsMap map[uint64]bool
|
||||
}
|
||||
|
||||
type PreParsedCommunityPermissionsData struct {
|
||||
*PreParsedPermissionsData
|
||||
Permissions []*CommunityTokenPermission
|
||||
}
|
||||
|
||||
func (p *DefaultPermissionChecker) getOwnedENS(addresses []gethcommon.Address) ([]string, error) {
|
||||
ownedENS := make([]string, 0)
|
||||
if p.ensVerifier == nil {
|
||||
|
@ -159,8 +171,8 @@ func (p *DefaultPermissionChecker) CheckPermissionToJoin(community *Community, a
|
|||
return becomeMemberPermissionsResponse, nil
|
||||
}
|
||||
// If there are any admin or token master permissions, combine result.
|
||||
|
||||
adminOrTokenPermissionsResponse, err := p.CheckPermissions(adminOrTokenMasterPermissionsToJoin, accountsAndChainIDs, false)
|
||||
preParsedPermissions := preParsedCommunityPermissionsData(adminOrTokenMasterPermissionsToJoin)
|
||||
adminOrTokenPermissionsResponse, err := p.CheckPermissions(preParsedPermissions, accountsAndChainIDs, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -191,13 +203,15 @@ func (p *DefaultPermissionChecker) checkPermissionsOrDefault(permissions []*Comm
|
|||
}
|
||||
return response, nil
|
||||
}
|
||||
return p.CheckPermissions(permissions, accountsAndChainIDs, false)
|
||||
|
||||
preParsedPermissions := preParsedCommunityPermissionsData(permissions)
|
||||
return p.CheckPermissions(preParsedPermissions, accountsAndChainIDs, false)
|
||||
}
|
||||
|
||||
// CheckPermissions will retrieve balances and check whether the user has
|
||||
// permission to join the community, if shortcircuit is true, it will stop as soon
|
||||
// as we know the answer
|
||||
func (p *DefaultPermissionChecker) CheckPermissions(permissions []*CommunityTokenPermission, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (*CheckPermissionsResponse, error) {
|
||||
func (p *DefaultPermissionChecker) CheckPermissions(permissionsParsedData *PreParsedCommunityPermissionsData, accountsAndChainIDs []*AccountChainIDsCombination, shortcircuit bool) (*CheckPermissionsResponse, error) {
|
||||
|
||||
response := &CheckPermissionsResponse{
|
||||
Satisfied: false,
|
||||
|
@ -205,30 +219,25 @@ func (p *DefaultPermissionChecker) CheckPermissions(permissions []*CommunityToke
|
|||
ValidCombinations: make([]*AccountChainIDsCombination, 0),
|
||||
}
|
||||
|
||||
erc20TokenRequirements, erc721TokenRequirements, _ := ExtractTokenCriteria(permissions)
|
||||
if permissionsParsedData == nil {
|
||||
response.Satisfied = true
|
||||
return response, nil
|
||||
}
|
||||
|
||||
erc20ChainIDsMap := make(map[uint64]bool)
|
||||
erc721ChainIDsMap := make(map[uint64]bool)
|
||||
erc721TokenRequirements := permissionsParsedData.Erc721TokenRequirements
|
||||
|
||||
erc20ChainIDsMap := permissionsParsedData.Erc20ChainIDsMap
|
||||
erc721ChainIDsMap := permissionsParsedData.Erc721ChainIDsMap
|
||||
|
||||
erc20TokenAddresses := permissionsParsedData.Erc20TokenAddresses
|
||||
|
||||
erc20TokenAddresses := make([]gethcommon.Address, 0)
|
||||
accounts := make([]gethcommon.Address, 0)
|
||||
|
||||
// TODO: move outside in order not to convert it
|
||||
for _, accountAndChainIDs := range accountsAndChainIDs {
|
||||
accounts = append(accounts, accountAndChainIDs.Address)
|
||||
}
|
||||
|
||||
// figure out chain IDs we're interested in
|
||||
for chainID, tokens := range erc20TokenRequirements {
|
||||
erc20ChainIDsMap[chainID] = true
|
||||
for contractAddress := range tokens {
|
||||
erc20TokenAddresses = append(erc20TokenAddresses, gethcommon.HexToAddress(contractAddress))
|
||||
}
|
||||
}
|
||||
|
||||
for chainID := range erc721TokenRequirements {
|
||||
erc721ChainIDsMap[chainID] = true
|
||||
}
|
||||
|
||||
chainIDsForERC20 := calculateChainIDsSet(accountsAndChainIDs, erc20ChainIDsMap)
|
||||
chainIDsForERC721 := calculateChainIDsSet(accountsAndChainIDs, erc721ChainIDsMap)
|
||||
|
||||
|
@ -260,7 +269,7 @@ func (p *DefaultPermissionChecker) CheckPermissions(permissions []*CommunityToke
|
|||
|
||||
accountsChainIDsCombinations := make(map[gethcommon.Address]map[uint64]bool)
|
||||
|
||||
for _, tokenPermission := range permissions {
|
||||
for _, tokenPermission := range permissionsParsedData.Permissions {
|
||||
|
||||
permissionRequirementsMet := true
|
||||
response.Permissions[tokenPermission.Id] = &PermissionTokenCriteriaResult{Role: tokenPermission.Type}
|
||||
|
@ -435,3 +444,64 @@ func (p *DefaultPermissionChecker) CheckPermissions(permissions []*CommunityToke
|
|||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func preParsedPermissionsData(permissions []*CommunityTokenPermission) *PreParsedPermissionsData {
|
||||
erc20TokenRequirements, erc721TokenRequirements, _ := ExtractTokenCriteria(permissions)
|
||||
|
||||
erc20ChainIDsMap := make(map[uint64]bool)
|
||||
erc721ChainIDsMap := make(map[uint64]bool)
|
||||
|
||||
erc20TokenAddresses := make([]gethcommon.Address, 0)
|
||||
|
||||
// figure out chain IDs we're interested in
|
||||
for chainID, tokens := range erc20TokenRequirements {
|
||||
erc20ChainIDsMap[chainID] = true
|
||||
for contractAddress := range tokens {
|
||||
erc20TokenAddresses = append(erc20TokenAddresses, gethcommon.HexToAddress(contractAddress))
|
||||
}
|
||||
}
|
||||
|
||||
for chainID := range erc721TokenRequirements {
|
||||
erc721ChainIDsMap[chainID] = true
|
||||
}
|
||||
|
||||
return &PreParsedPermissionsData{
|
||||
Erc721TokenRequirements: erc721TokenRequirements,
|
||||
Erc20TokenAddresses: erc20TokenAddresses,
|
||||
Erc20ChainIDsMap: erc20ChainIDsMap,
|
||||
Erc721ChainIDsMap: erc721ChainIDsMap,
|
||||
}
|
||||
}
|
||||
|
||||
func preParsedCommunityPermissionsData(permissions []*CommunityTokenPermission) *PreParsedCommunityPermissionsData {
|
||||
if len(permissions) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &PreParsedCommunityPermissionsData{
|
||||
Permissions: permissions,
|
||||
PreParsedPermissionsData: preParsedPermissionsData(permissions),
|
||||
}
|
||||
}
|
||||
|
||||
func PreParsePermissionsData(permissions map[string]*CommunityTokenPermission) (map[protobuf.CommunityTokenPermission_Type]*PreParsedCommunityPermissionsData, map[string]*PreParsedCommunityPermissionsData) {
|
||||
becomeMemberPermissions := TokenPermissionsByType(permissions, protobuf.CommunityTokenPermission_BECOME_MEMBER)
|
||||
becomeAdminPermissions := TokenPermissionsByType(permissions, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
||||
becomeTokenMasterPermissions := TokenPermissionsByType(permissions, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER)
|
||||
|
||||
viewOnlyPermissions := TokenPermissionsByType(permissions, protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL)
|
||||
viewAndPostPermissions := TokenPermissionsByType(permissions, protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL)
|
||||
channelPermissions := append(viewAndPostPermissions, viewOnlyPermissions...)
|
||||
|
||||
communityPermissionsPreParsedData := make(map[protobuf.CommunityTokenPermission_Type]*PreParsedCommunityPermissionsData)
|
||||
communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_MEMBER] = preParsedCommunityPermissionsData(becomeMemberPermissions)
|
||||
communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_ADMIN] = preParsedCommunityPermissionsData(becomeAdminPermissions)
|
||||
communityPermissionsPreParsedData[protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER] = preParsedCommunityPermissionsData(becomeTokenMasterPermissions)
|
||||
|
||||
channelPermissionsPreParsedData := make(map[string]*PreParsedCommunityPermissionsData)
|
||||
for _, channelPermission := range channelPermissions {
|
||||
channelPermissionsPreParsedData[channelPermission.Id] = preParsedCommunityPermissionsData([]*CommunityTokenPermission{channelPermission})
|
||||
}
|
||||
|
||||
return communityPermissionsPreParsedData, channelPermissionsPreParsedData
|
||||
}
|
||||
|
|
|
@ -2055,3 +2055,59 @@ func (p *Persistence) getDecryptedCommunityDescriptionByID(tx *sql.Tx, community
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Persistence) GetCommunityRequestsToJoinRevealedAddresses(communityID []byte) (map[string][]*protobuf.RevealedAccount, error) {
|
||||
accounts := make(map[string][]*protobuf.RevealedAccount)
|
||||
|
||||
rows, err := p.db.Query(`
|
||||
SELECT r.public_key,
|
||||
a.address, a.chain_ids, a.is_airdrop_address, a.signature
|
||||
FROM communities_requests_to_join r
|
||||
LEFT JOIN communities_requests_to_join_revealed_addresses a ON r.id = a.request_id
|
||||
WHERE r.community_id = ? AND r.state = ?`, communityID, RequestToJoinStateAccepted)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return accounts, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var rawPublicKey sql.NullString
|
||||
var address sql.NullString
|
||||
var chainIDsStr sql.NullString
|
||||
var isAirdropAddress sql.NullBool
|
||||
var signature sql.RawBytes
|
||||
|
||||
err = rows.Scan(&rawPublicKey, &address, &chainIDsStr, &isAirdropAddress, &signature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !rawPublicKey.Valid {
|
||||
return nil, errors.New("GetCommunityRequestsToJoinRevealedAddresses: invalid public key")
|
||||
}
|
||||
|
||||
publicKey := rawPublicKey.String
|
||||
|
||||
revealedAccount, err := toRevealedAccount(address, chainIDsStr, isAirdropAddress, signature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if revealedAccount == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exists := accounts[publicKey]; !exists {
|
||||
accounts[publicKey] = []*protobuf.RevealedAccount{revealedAccount}
|
||||
} else {
|
||||
accounts[publicKey] = append(accounts[publicKey], revealedAccount)
|
||||
}
|
||||
}
|
||||
|
||||
return accounts, nil
|
||||
}
|
||||
|
|
|
@ -1051,3 +1051,55 @@ func (s *PersistenceSuite) TestDecryptedCommunityCacheClock() {
|
|||
s.Require().NoError(err)
|
||||
s.Require().Equal(count, 1)
|
||||
}
|
||||
|
||||
func (s *PersistenceSuite) TestGetCommunityRequestsToJoinRevealedAddresses() {
|
||||
clock := uint64(time.Now().Unix())
|
||||
communityID := types.HexBytes{7, 7, 7, 7, 7, 7, 7, 7}
|
||||
revealedAddress := "address1"
|
||||
chainIds := []uint64{1, 2}
|
||||
publicKey := common.PubkeyToHex(&s.identity.PublicKey)
|
||||
signature := []byte("test")
|
||||
|
||||
// No data in database
|
||||
accounts, err := s.db.GetCommunityRequestsToJoinRevealedAddresses(communityID)
|
||||
s.Require().NoError(err)
|
||||
_, exists := accounts[publicKey]
|
||||
s.Require().False(exists)
|
||||
|
||||
expectedRtj := &RequestToJoin{
|
||||
ID: types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8},
|
||||
PublicKey: publicKey,
|
||||
Clock: clock,
|
||||
CommunityID: communityID,
|
||||
State: RequestToJoinStateAccepted,
|
||||
RevealedAccounts: []*protobuf.RevealedAccount{
|
||||
{
|
||||
Address: revealedAddress,
|
||||
ChainIds: chainIds,
|
||||
IsAirdropAddress: true,
|
||||
Signature: signature,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Request to join was stored without revealed account
|
||||
err = s.db.SaveRequestToJoin(expectedRtj)
|
||||
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
||||
|
||||
// revealed account is absent
|
||||
accounts, err = s.db.GetCommunityRequestsToJoinRevealedAddresses(communityID)
|
||||
s.Require().NoError(err, "RevealedAccounts empty, shouldn't give any error")
|
||||
|
||||
_, exists = accounts[publicKey]
|
||||
s.Require().False(exists)
|
||||
|
||||
// save revealed accounts for the previous request to join
|
||||
err = s.db.SaveRequestToJoinRevealedAddresses(expectedRtj.ID, expectedRtj.RevealedAccounts)
|
||||
s.Require().NoError(err)
|
||||
|
||||
accounts, err = s.db.GetCommunityRequestsToJoinRevealedAddresses(communityID)
|
||||
s.Require().NoError(err)
|
||||
memberAccounts, exists := accounts[publicKey]
|
||||
s.Require().True(exists)
|
||||
s.Require().Len(memberAccounts, 1)
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ func ExtractTokenCriteria(permissions []*CommunityTokenPermission) (erc20TokenCr
|
|||
if isERC20 && !existsERC20 {
|
||||
erc20TokenCriteria[chainID] = make(map[string]*protobuf.TokenCriteria)
|
||||
}
|
||||
|
||||
// TODO: check if we do not duplicate this due to ToLower case
|
||||
_, existsERC721 = erc721TokenCriteria[chainID][contractAddress]
|
||||
if isERC721 && !existsERC721 {
|
||||
erc721TokenCriteria[chainID][strings.ToLower(contractAddress)] = tokenRequirement
|
||||
|
|
|
@ -3619,7 +3619,8 @@ func (t *testPermissionChecker) CheckPermissionToJoin(*communities.Community, []
|
|||
return &communities.CheckPermissionsResponse{Satisfied: true}, nil
|
||||
|
||||
}
|
||||
func (t *testPermissionChecker) CheckPermissions(permissions []*communities.CommunityTokenPermission, accountsAndChainIDs []*communities.AccountChainIDsCombination, shortcircuit bool) (*communities.CheckPermissionsResponse, error) {
|
||||
|
||||
func (t *testPermissionChecker) CheckPermissions(permissionsParsedData *communities.PreParsedCommunityPermissionsData, accountsAndChainIDs []*communities.AccountChainIDsCombination, shortcircuit bool) (*communities.CheckPermissionsResponse, error) {
|
||||
return &communities.CheckPermissionsResponse{Satisfied: true}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,13 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/zap"
|
||||
|
||||
|
@ -2011,3 +2013,122 @@ func (s *MessengerCommunitiesTokenPermissionsSuite) TestResendEncryptionKeyOnBac
|
|||
s.Require().NoError(err)
|
||||
s.Require().Len(response.Messages(), 1)
|
||||
}
|
||||
|
||||
func (s *MessengerCommunitiesTokenPermissionsSuite) TestReevaluateMemberPermissionsPerformance() {
|
||||
// This test is created for a performance degradation tracking for reevaluateMember permissions
|
||||
// current scenario mostly track channels permissions reevaluating, but feel free to expand it to
|
||||
// other scenarios or test you performance improvements
|
||||
|
||||
// in average, it took nearly 100-105 ms to check one permission for a current scenario:
|
||||
// - 10 members
|
||||
// - 10 channels
|
||||
// - one permission (channel permission for all 10 channels is set up)
|
||||
|
||||
// currently, adding any new permission to test must twice the current test average time
|
||||
|
||||
community, chat := s.createCommunity()
|
||||
|
||||
community, err := s.owner.communitiesManager.GetByID(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(community.Chats(), 2)
|
||||
|
||||
requestToJoin := &communities.RequestToJoin{
|
||||
Clock: uint64(time.Now().Unix()),
|
||||
CommunityID: community.ID(),
|
||||
State: communities.RequestToJoinStateAccepted,
|
||||
RevealedAccounts: []*protobuf.RevealedAccount{
|
||||
{
|
||||
Address: bobAddress,
|
||||
ChainIds: []uint64{testChainID1},
|
||||
IsAirdropAddress: true,
|
||||
Signature: []byte("test"),
|
||||
},
|
||||
},
|
||||
}
|
||||
communityRole := []protobuf.CommunityMember_Roles{}
|
||||
|
||||
keysCount := 10
|
||||
|
||||
for i := 0; i < keysCount; i++ {
|
||||
privateKey, err := crypto.GenerateKey()
|
||||
s.Require().NoError(err)
|
||||
|
||||
memberPubKeyStr := common.PubkeyToHex(&privateKey.PublicKey)
|
||||
requestId := communities.CalculateRequestID(memberPubKeyStr, community.ID())
|
||||
requestToJoin.ID = requestId
|
||||
requestToJoin.PublicKey = memberPubKeyStr
|
||||
|
||||
err = s.owner.communitiesManager.SaveRequestToJoin(requestToJoin)
|
||||
s.Require().NoError(err)
|
||||
err = s.owner.communitiesManager.SaveRequestToJoinRevealedAddresses(requestId, requestToJoin.RevealedAccounts)
|
||||
s.Require().NoError(err)
|
||||
_, err = community.AddMember(&privateKey.PublicKey, communityRole)
|
||||
s.Require().NoError(err)
|
||||
_, err = community.AddMemberToChat(chat.CommunityChatID(), &privateKey.PublicKey, communityRole, protobuf.CommunityMember_CHANNEL_ROLE_POSTER)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
s.Require().Equal(community.MembersCount(), keysCount+1) // 1 is owner
|
||||
|
||||
chatsCount := 8 // in total will be 10, 2 channels were created during creating the community
|
||||
|
||||
for i := 0; i < chatsCount; i++ {
|
||||
newChat := &protobuf.CommunityChat{
|
||||
Permissions: &protobuf.CommunityPermissions{
|
||||
Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
|
||||
},
|
||||
Identity: &protobuf.ChatIdentity{
|
||||
DisplayName: "name-" + strconv.Itoa(i),
|
||||
Description: "",
|
||||
},
|
||||
}
|
||||
|
||||
chatID := uuid.New().String()
|
||||
_, err = community.CreateChat(chatID, newChat)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
s.Require().Len(community.Chats(), chatsCount+2) // 2 chats were created during community creation
|
||||
|
||||
err = s.owner.communitiesManager.SaveCommunity(community)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// setup view channel permission
|
||||
channelPermissionRequest := requests.CreateCommunityTokenPermission{
|
||||
CommunityID: community.ID(),
|
||||
Type: protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
|
||||
TokenCriteria: []*protobuf.TokenCriteria{
|
||||
&protobuf.TokenCriteria{
|
||||
Type: protobuf.CommunityTokenType_ERC20,
|
||||
ContractAddresses: map[uint64]string{testChainID1: "0x123"},
|
||||
Symbol: "TEST",
|
||||
AmountInWei: "100000000000000000000",
|
||||
Decimals: uint64(18),
|
||||
},
|
||||
},
|
||||
ChatIds: community.ChatIDs(),
|
||||
}
|
||||
|
||||
s.makeAddressSatisfyTheCriteria(testChainID1, bobAddress, channelPermissionRequest.TokenCriteria[0])
|
||||
defer s.resetMockedBalances() // reset mocked balances, this test in run with different test cases
|
||||
|
||||
// create permission using communitiesManager in order not to launch blocking reevaluation loop
|
||||
community, _, err = s.owner.communitiesManager.CreateCommunityTokenPermission(&channelPermissionRequest)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(community.TokenPermissions(), 1)
|
||||
|
||||
for _, ids := range community.ChatIDs() {
|
||||
s.Require().True(s.owner.communitiesManager.IsChannelEncrypted(community.IDString(), ids))
|
||||
}
|
||||
|
||||
// force owner to reevaluate channel members
|
||||
// in production it will happen automatically, by periodic check
|
||||
start := time.Now()
|
||||
_, _, err = s.owner.communitiesManager.ReevaluateMembers(community.ID())
|
||||
s.Require().NoError(err)
|
||||
|
||||
elapsed := time.Since(start)
|
||||
|
||||
fmt.Println("ReevaluateMembers Time: ", elapsed)
|
||||
s.Require().Less(elapsed.Seconds(), 2.0)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue