Skip to content

Commit

Permalink
Merge pull request #3 from deso-protocol/p/k-group-muting
Browse files Browse the repository at this point in the history
P/k group muting
  • Loading branch information
keshavm02 authored Sep 2, 2022
2 parents d40702c + c9242e2 commit 366deff
Show file tree
Hide file tree
Showing 14 changed files with 166 additions and 175 deletions.
6 changes: 3 additions & 3 deletions lib/block_view_derived_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2599,10 +2599,10 @@ func TestAuthorizedDerivedKeyWithTransactionLimitsHardcore(t *testing.T) {
testStage := TestStageBeforeUnlimitedDerivedBlockHeight

GlobalDeSoParams = *params
GlobalDeSoParams.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight = unlimitedDerivedKeysBlockHeight
GlobalDeSoParams.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight = unlimitedDerivedKeysBlockHeight
for ii := range GlobalDeSoParams.EncoderMigrationHeightsList {
migration := GlobalDeSoParams.EncoderMigrationHeightsList[ii]
if migration.Name == DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimization {
if migration.Name == DeSoUnlimitedDerivedKeysAndMessageMutingAndMembershipIndex {
GlobalDeSoParams.EncoderMigrationHeightsList[ii].Height = uint64(unlimitedDerivedKeysBlockHeight)
} else {
GlobalDeSoParams.EncoderMigrationHeightsList[ii].Height = 0
Expand All @@ -2616,7 +2616,7 @@ func TestAuthorizedDerivedKeyWithTransactionLimitsHardcore(t *testing.T) {
params.ForkHeights.DAOCoinLimitOrderBlockHeight = uint32(0)
params.ForkHeights.OrderBookDBFetchOptimizationBlockHeight = uint32(0)
params.ForkHeights.BuyNowAndNFTSplitsBlockHeight = uint32(0)
params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight = uint32(0)
params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight = uint32(0)
params.ForkHeights.DerivedKeyEthSignatureCompatibilityBlockHeight = uint32(0)

params.ExtraRegtestParamUpdaterKeys[MakePkMapKey(paramUpdaterPkBytes)] = true
Expand Down
16 changes: 8 additions & 8 deletions lib/block_view_flush.go
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ func (bav *UtxoView) _flushMessagingGroupEntriesToDbWithTxn(txn *badger.Txn, blo
// Note that the latter for-loop over the MessagingGroupMembers doesn't conflict with this delete.
// If a membership index entry with key <ownerPublicKey, ownerPublicKey, keyName> was part of the
// MessagingGroupMembers, it just gets deleted anyway.
if blockHeight >= uint64(bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight) {
if blockHeight >= uint64(bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight) {
// Group owner is added as member by default in the new fork. More on this in the later comment.
// We make sure to delete the owner from the membership index.
if err := DBDeleteMessagingGroupOwnerFromMembershipIndexWithTxn(
Expand All @@ -996,7 +996,7 @@ func (bav *UtxoView) _flushMessagingGroupEntriesToDbWithTxn(txn *badger.Txn, blo
// Prior to the fork, group members were stored under the deprecated index. After the fork,
// all members are stored in the new membership index. Depending on the blockheight, we remove
// existing entries from the corresponding index.
if blockHeight < uint64(bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight) {
if blockHeight < uint64(bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight) {
if err := DEPRECATEDDBDeleteMessagingGroupMemberMappingWithTxn(txn, bav.Snapshot,
member, existingMessagingGroupEntry); err != nil {
return errors.Wrapf(err, "UtxoView._flushMessagingGroupEntriesToDbWithTxn: "+
Expand Down Expand Up @@ -1025,9 +1025,9 @@ func (bav *UtxoView) _flushMessagingGroupEntriesToDbWithTxn(txn *badger.Txn, blo
if err := DBPutMessagingGroupEntryWithTxn(txn, bav.Snapshot, blockHeight,
ownerPublicKey, messagingGroupEntry); err != nil {
return errors.Wrapf(err, "UtxoView._flushMessagingGroupEntriesToDbWithTxn: "+
"Problem putting MessagingGroupEntry %v to db", *messagingGroupEntry)
"Fail while putting group entry. Problem putting MessagingGroupEntry %v to db", *messagingGroupEntry)
}
if blockHeight >= uint64(bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight) {
if blockHeight >= uint64(bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight) {
// Group owner can be one of the group members, particularly when we want to add the
// encrypted key addressed to the owner. This could happen when the group is created
// by a derived key, and we want to allow the main owner key to be able to read the chat.
Expand All @@ -1038,7 +1038,7 @@ func (bav *UtxoView) _flushMessagingGroupEntriesToDbWithTxn(txn *badger.Txn, blo
if err := DBPutMessagingGroupOwnerInMembershipIndexWithTxn(txn, bav.Snapshot, blockHeight,
ownerPublicKey, messagingGroupEntry); err != nil {
return errors.Wrapf(err, "UtxoView._flushMessagingGroupEntriesToDbWithTxn: "+
"Problem putting MessagingGroupEntry %v to db", *messagingGroupEntry)
"Fail while putting owner membership index. Problem putting MessagingGroupEntry %v to db", *messagingGroupEntry)
}
}
for _, member := range messagingGroupEntry.MessagingGroupMembers {
Expand All @@ -1047,17 +1047,17 @@ func (bav *UtxoView) _flushMessagingGroupEntriesToDbWithTxn(txn *badger.Txn, blo
// entries to the corresponding index.
// The membership index allows us to store only the relevant member in the lists - "MessagingGroupMembers" &
// "MuteList" which otherwise could have been pretty bulky to retrieve for every single message.
if blockHeight < uint64(bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight) {
if blockHeight < uint64(bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight) {
if err := DEPRECATEDDBPutMessagingGroupMemberWithTxn(txn, bav.Snapshot, blockHeight,
member, ownerPublicKey, messagingGroupEntry); err != nil {
return errors.Wrapf(err, "UtxoView._flushMessagingGroupEntriesToDbWithTxn: "+
"Problem putting MessagingGroupEntry member (%v) to db", member)
"Fail while putting old membership index. Problem putting MessagingGroupEntry member (%v) to db", *member)
}
} else {
if err := DBPutMessagingGroupMemberInMembershipIndexWithTxn(txn, bav.Snapshot, blockHeight,
member, messagingGroupEntry); err != nil {
return errors.Wrapf(err, "UtxoView._flushMessagingGroupEntriesToDbWithTxn: "+
"Problem putting MessagingGroupEntry member (%v) to db", member)
"Fail while putting new membership index. Problem putting MessagingGroupEntry member (%v) to db", *member)
}
}

Expand Down
77 changes: 48 additions & 29 deletions lib/block_view_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (bav *UtxoView) GetMessagingMemberEntry(memberPublicKey *PublicKey, groupOw
// GetMessagingMemberEntry compatible with the new membership index, that's why we don't attempt to fetch entries from
// the deprecated prefix, even though it would have saved us some read time. The call to
// GetMessagingGroupKeyToMessagingGroupEntryMapping will fetch the full entry.
if len(forceFullEntry) == 0 && blockHeight >= bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight {
if len(forceFullEntry) == 0 && blockHeight >= bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight {
messagingGroupEntry := DBGetEntryFromMembershipIndex(bav.Handle, bav.Snapshot, memberPublicKey, groupOwnerPublicKey, groupKeyName)
if messagingGroupEntry != nil {
return messagingGroupEntry
Expand Down Expand Up @@ -266,7 +266,7 @@ func (bav *UtxoView) GetMessagingGroupEntriesForUser(ownerPublicKey []byte, bloc
// We fetched all the entries from the UtxoView, so we move to the DB.
var dbMessagingKeys []*MessagingGroupEntry
var err error
if blockHeight >= bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight {
if blockHeight >= bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight {
dbMessagingKeys, err = DBGetAllUserGroupEntries(bav.Handle, ownerPublicKey)
if err != nil {
return nil, errors.Wrapf(err, "GetUserMessagingKeys: problem getting "+
Expand Down Expand Up @@ -570,13 +570,13 @@ func (bav *UtxoView) _connectPrivateMessage(
messageEntry.RecipientMessagingGroupKeyName = NewGroupKeyName(recipientMessagingKeyName)
}

// After the DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight block height we force the usage of V3 messages.
if blockHeight >= bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight {
// After the DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight block height we force the usage of V3 messages.
if blockHeight >= bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight {
if !(existsSender && existsSenderName && existsRecipient && existsRecipientName) {
return 0, 0, nil, errors.Wrapf(
RuleErrorPrivateMessageSentWithoutProperMessagingParty,
"_connectPrivateMessage: SenderKey, SenderName, RecipientKey, RecipientName should all exist "+
"in ExtraData after DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight.")
"in ExtraData after DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight.")
}
// Reject message if sender is muted
// Here we retrieve the MuteList in an optimized way by using the <MembershipIndex> prefix
Expand Down Expand Up @@ -929,7 +929,7 @@ func (bav *UtxoView) _connectMessagingGroup(

// Determine the messaging group operation.
var messagingGroupOperation MessagingGroupOperation
if blockHeight < bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndV3MessagesMutingAndPrefixOptimizationBlockHeight {
if blockHeight < bav.Params.ForkHeights.DeSoUnlimitedDerivedKeysAndMessagesMutingAndMembershipIndexBlockHeight {
messagingGroupOperation = MessagingGroupOperationAddMembers
} else {
messagingGroupOperation, err = GetMessagingGroupOperation(txn)
Expand Down Expand Up @@ -968,10 +968,10 @@ func (bav *UtxoView) _connectMessagingGroup(
// all valid members.

// Map all members so that it's easier to check for overlapping members.
existingMembers := make(map[PublicKey]bool)
existingMembers := make(map[PublicKey]struct{})

// Sanity-check a group's members can't contain the messagingPublicKey.
existingMembers[*messagingPublicKey] = true
existingMembers[*messagingPublicKey] = struct{}{}

// If we're adding more group members, then we need to make sure there are no overlapping members between the
// transaction's entry, and the existing entry.
Expand All @@ -991,7 +991,7 @@ func (bav *UtxoView) _connectMessagingGroup(
}

// Add the existingMember to our helper structs.
existingMembers[*existingMember.GroupMemberPublicKey] = true
existingMembers[*existingMember.GroupMemberPublicKey] = struct{}{}
newMessagingMembers = append(newMessagingMembers, existingMember)
}
// Set the mute list to the existing mute list since we won't be changing it.
Expand Down Expand Up @@ -1037,15 +1037,15 @@ func (bav *UtxoView) _connectMessagingGroup(
"Error, messagingMember already exists (%v)", messagingMember.GroupMemberPublicKey[:])
}
// Add the messagingMember to our helper structs.
existingMembers[*messagingMember.GroupMemberPublicKey] = true
existingMembers[*messagingMember.GroupMemberPublicKey] = struct{}{}
newMessagingMembers = append(newMessagingMembers, messagingMember)
}

case MessagingGroupOperationMuteMembers:
// Muting members assumes the group was already created.
if existingEntry == nil || existingEntry.isDeleted {
return 0, 0, nil, errors.Wrapf(RuleErrorMessagingGroupDoesntExist,
"_connectMessagingGroup: Can't mute members for a non-existing group")
"_connectMessagingGroup: Can't mute members for a non-existent group")
}
// MUTING/UNMUTING functionality notes:
// In DeSo V3 Messages, Group Chat Owners can now mute or unmute members. This essentially acts like a
Expand All @@ -1057,8 +1057,15 @@ func (bav *UtxoView) _connectMessagingGroup(
// the message is muted or not. This would decide whether we reject a message txn or not. However, to check
// that, we can't just fetch the entire MessagingGroupEntry which may contains 1000s if not 100,000s of members.
// Instead, we will make usage of the membership index. We will especially see this in the flushing logic.
for _, existingMutedMember := range existingEntry.MuteList {
newMuteList = append(newMuteList, existingMutedMember)
existingMutedMembers := make(map[PublicKey]struct{})
for _, mutedMember := range existingEntry.MuteList {
existingMutedMembers[*mutedMember.GroupMemberPublicKey] = struct{}{}
newMuteList = append(newMuteList, mutedMember)
}
// We will keep this map to keep track of all members in the group.
existingGroupMembers := make(map[PublicKey]struct{})
for _, groupMember := range existingEntry.MessagingGroupMembers {
existingGroupMembers[*groupMember.GroupMemberPublicKey] = struct{}{}
}

for _, newlyMutedMember := range txMeta.MessagingGroupMembers {
Expand All @@ -1067,13 +1074,20 @@ func (bav *UtxoView) _connectMessagingGroup(
return 0, 0, nil, errors.Wrapf(RuleErrorMessagingGroupOwnerMutingSelf,
"_connectMessagingGroup: GroupOwner cannot mute herself (%v).", existingEntry.GroupOwnerPublicKey[:])
}
// Make sure we are muting a member that exists in the group.
if _, exists := existingGroupMembers[*newlyMutedMember.GroupMemberPublicKey]; !exists {
return 0, 0, nil, errors.Wrapf(RuleErrorMessagingMemberDoesntExist,
"_connectMessagingGroup: Can't mute a non-existent member (%v)", newlyMutedMember.GroupMemberPublicKey[:])
}

// Add member to newMuteList. We iterate over newMuteList to prevent mute list entries with duplicate public keys.
for _, addedMutedMember := range newMuteList {
if _, exists := existingMutedMembers[*newlyMutedMember.GroupMemberPublicKey]; !exists {
newMuteList = append(newMuteList, newlyMutedMember)
existingMutedMembers[*newlyMutedMember.GroupMemberPublicKey] = struct{}{}
} else {
// Check if member is already muted, in such case we error.
if reflect.DeepEqual(addedMutedMember.GroupMemberPublicKey[:], newlyMutedMember.GroupMemberPublicKey[:]) {
return 0, 0, nil, errors.Wrapf(RuleErrorMessagingMemberAlreadyMuted,
"_connectMessagingGroup: Cannot mute member that is already muted (%v).", newlyMutedMember.GroupMemberPublicKey[:])
}
return 0, 0, nil, errors.Wrapf(RuleErrorMessagingMemberAlreadyMuted,
"_connectMessagingGroup: Cannot mute member that is already muted (%v).", newlyMutedMember.GroupMemberPublicKey[:])
}
// Check if newlyMutedMember is a valid member of existingEntry.MessagingGroupMembers. If not, error.
memberExists := false
Expand All @@ -1096,20 +1110,21 @@ func (bav *UtxoView) _connectMessagingGroup(
// Unmuting members assumes the group was already created.
if existingEntry == nil || existingEntry.isDeleted {
return 0, 0, nil, errors.Wrapf(RuleErrorMessagingGroupDoesntExist,
"_connectMessagingGroup: Can't mute members for a non-existing group")
"_connectMessagingGroup: Can't mute members for a non-existent group")
}
// Keep track of all muted members.
existingMutedMembers := make(map[PublicKey]*MessagingGroupMember)
for _, mutedMember := range existingEntry.MuteList {
existingMutedMembers[*mutedMember.GroupMemberPublicKey] = mutedMember
}
for _, member := range txMeta.MessagingGroupMembers {
isUnmuteValid := false
// re-add all muted members except for the member that we're trying to unmute.
newMuteList = []*MessagingGroupMember{}
for _, toUnmute := range existingEntry.MuteList {
// if member not in MuteList, add member to the tempMuteList
if !reflect.DeepEqual(toUnmute.GroupMemberPublicKey[:], member.GroupMemberPublicKey[:]) {
newMuteList = append(newMuteList, toUnmute)
} else {
// if member IS in MuteList, then unmute txn is valid, and we continue looping to add remaining members to newMuteList.
isUnmuteValid = true
}
// re-add all muted members except for the member that we're trying to unmute. Check if the member exists
// in the mute-list, otherwise we can't unmute them.
if _, exists := existingMutedMembers[*member.GroupMemberPublicKey]; exists {
isUnmuteValid = true
// Unmute the member by deleting it from the helper map of muted members. We will later turn it into the newMuteList.
delete(existingMutedMembers, *member.GroupMemberPublicKey)
}
// If invalid unmuting, then check why:
// 1. GroupOwner unmuting herself
Expand All @@ -1133,6 +1148,10 @@ func (bav *UtxoView) _connectMessagingGroup(
"_connectMessagingGroup: Cannot unmute member that does not exist in group (%v).", member.GroupMemberPublicKey[:])
}
}
// Add all members from the existingMutedMembers to the newMuteList
for _, mutedMember := range existingMutedMembers {
newMuteList = append(newMuteList, mutedMember)
}
// Set the messaging members to the existing members since we won't be changing them.
newMessagingMembers = existingEntry.MessagingGroupMembers
default:
Expand Down
Loading

0 comments on commit 366deff

Please sign in to comment.