fix: Prevent (reject event <-> resend event) loop (#4055)

This commit is contained in:
Mykhailo Prakhov 2023-09-22 19:57:27 +02:00 committed by GitHub
parent 0f065a9f07
commit 2b53d71708
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 0 deletions

View File

@ -1425,6 +1425,8 @@ func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message
err = community.UpdateCommunityByEvents(eventsMessage)
if err != nil {
if err == ErrInvalidCommunityEventClock && community.IsControlNode() {
// send updated CommunityDescription to the event sender on top of which he must apply his changes
eventsMessage.EventsBaseCommunityDescription = community.config.CommunityDescriptionProtocolMessage
m.publish(&Subscription{
CommunityEventsMessageInvalidClock: &CommunityEventsMessageInvalidClockSignal{
Community: community,
@ -1491,6 +1493,17 @@ func (m *Manager) HandleCommunityEventsMessageRejected(signer *ecdsa.PublicKey,
if err != nil {
return nil, err
}
communityDescription, err := validateAndGetEventsMessageCommunityDescription(eventsMessage.EventsBaseCommunityDescription, signer)
if err != nil {
return nil, err
}
// the privileged member did not receive updated CommunityDescription so his events
// will be send on top of outdated CommunityDescription
if communityDescription.Clock != community.Clock() {
return nil, errors.New("resend rejected community events aborted, client node has outdated community description")
}
eventsMessage.Events = m.validateAndFilterEvents(community, eventsMessage.Events)
myRejectedEvents := make([]CommunityEvent, 0)
@ -4813,3 +4826,7 @@ func (m *Manager) shareAcceptedRequestToJoinWithPrivilegedMembers(community *Com
func (m *Manager) GetCommunityRequestsToJoinWithRevealedAddresses(communityID types.HexBytes) ([]*RequestToJoin, error) {
return m.persistence.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
}
func (m *Manager) SaveCommunity(community *Community) error {
return m.persistence.SaveCommunity(community)
}

View File

@ -381,3 +381,62 @@ func (s *AdminCommunityEventsSuite) TestReceiveRequestsToJoinWithRevealedAccount
bob := s.newMessenger(accountPassword, []string{bobAccountAddress})
testMemberReceiveRequestsToJoinAfterGettingNewRole(s, bob, protobuf.CommunityTokenPermission_BECOME_ADMIN)
}
func (s *AdminCommunityEventsSuite) TestAdminDoesNotHaveRejectedEventsLoop() {
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
// admin modifies community description
adminEditRequest := &requests.EditCommunity{
CommunityID: community.ID(),
CreateCommunity: requests.CreateCommunity{
Name: "admin name",
Description: "admin description",
Color: "#FFFFFF",
Membership: protobuf.CommunityPermissions_ON_REQUEST,
},
}
_, err := s.admin.EditCommunity(adminEditRequest)
s.Require().NoError(err)
community, err = s.owner.communitiesManager.GetByID(community.ID())
s.Require().NoError(err)
// Update community clock without publishing new CommunityDescription
err = community.DeclineRequestToJoin(nil)
s.Require().NoError(err)
err = s.owner.communitiesManager.SaveCommunity(community)
s.Require().NoError(err)
waitOnAdminEventsRejection := waitOnCommunitiesEvent(s.owner, func(s *communities.Subscription) bool {
return s.CommunityEventsMessageInvalidClock != nil
})
// control node receives admin event and rejects it
_, err = WaitOnMessengerResponse(s.owner, func(response *MessengerResponse) bool {
select {
case err := <-waitOnAdminEventsRejection:
s.Require().NoError(err)
return true
default:
return false
}
}, "")
s.Require().NoError(err)
community, err = s.owner.communitiesManager.GetByID(community.ID())
s.Require().NoError(err)
s.Require().NotEqual(adminEditRequest.Description, community.DescriptionText())
// admin receives rejected events and re-applies them
// there is no signal whatsoever, we just wait for admin to process all incoming messages
_, _ = WaitOnMessengerResponse(s.admin, func(response *MessengerResponse) bool {
return false
}, "")
// control node does not receives admin event
_, err = WaitOnMessengerResponse(s.owner, func(response *MessengerResponse) bool {
return len(response.Communities()) > 0
}, "no communities in response")
s.Require().Error(err)
}