fix: Prevent (reject event <-> resend event) loop (#4055)
This commit is contained in:
parent
0f065a9f07
commit
2b53d71708
|
@ -1425,6 +1425,8 @@ func (m *Manager) HandleCommunityEventsMessage(signer *ecdsa.PublicKey, message
|
||||||
err = community.UpdateCommunityByEvents(eventsMessage)
|
err = community.UpdateCommunityByEvents(eventsMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == ErrInvalidCommunityEventClock && community.IsControlNode() {
|
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{
|
m.publish(&Subscription{
|
||||||
CommunityEventsMessageInvalidClock: &CommunityEventsMessageInvalidClockSignal{
|
CommunityEventsMessageInvalidClock: &CommunityEventsMessageInvalidClockSignal{
|
||||||
Community: community,
|
Community: community,
|
||||||
|
@ -1491,6 +1493,17 @@ func (m *Manager) HandleCommunityEventsMessageRejected(signer *ecdsa.PublicKey,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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)
|
eventsMessage.Events = m.validateAndFilterEvents(community, eventsMessage.Events)
|
||||||
|
|
||||||
myRejectedEvents := make([]CommunityEvent, 0)
|
myRejectedEvents := make([]CommunityEvent, 0)
|
||||||
|
@ -4813,3 +4826,7 @@ func (m *Manager) shareAcceptedRequestToJoinWithPrivilegedMembers(community *Com
|
||||||
func (m *Manager) GetCommunityRequestsToJoinWithRevealedAddresses(communityID types.HexBytes) ([]*RequestToJoin, error) {
|
func (m *Manager) GetCommunityRequestsToJoinWithRevealedAddresses(communityID types.HexBytes) ([]*RequestToJoin, error) {
|
||||||
return m.persistence.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
|
return m.persistence.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) SaveCommunity(community *Community) error {
|
||||||
|
return m.persistence.SaveCommunity(community)
|
||||||
|
}
|
||||||
|
|
|
@ -381,3 +381,62 @@ func (s *AdminCommunityEventsSuite) TestReceiveRequestsToJoinWithRevealedAccount
|
||||||
bob := s.newMessenger(accountPassword, []string{bobAccountAddress})
|
bob := s.newMessenger(accountPassword, []string{bobAccountAddress})
|
||||||
testMemberReceiveRequestsToJoinAfterGettingNewRole(s, bob, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue