This commit is contained in:
parent
53ac61bb8b
commit
405d468e0e
|
@ -1372,6 +1372,10 @@ func (o *Community) Description() *protobuf.CommunityDescription {
|
|||
return o.config.CommunityDescription
|
||||
}
|
||||
|
||||
func (o *Community) DescriptionProtocolMessage() []byte {
|
||||
return o.config.CommunityDescriptionProtocolMessage
|
||||
}
|
||||
|
||||
func (o *Community) marshaledDescription() ([]byte, error) {
|
||||
clone := proto.Clone(o.config.CommunityDescription).(*protobuf.CommunityDescription)
|
||||
|
||||
|
|
|
@ -1638,7 +1638,12 @@ func (m *Manager) HandleCommunityDescriptionMessage(signer *ecdsa.PublicKey, des
|
|||
|
||||
if hasTokenOwnership && verifiedOwner != nil {
|
||||
// Override verified owner
|
||||
m.logger.Info("updating verified owner", zap.String("communityID", community.IDString()), zap.String("owner", common.PubkeyToHex(verifiedOwner)))
|
||||
m.logger.Info("updating verified owner",
|
||||
zap.String("communityID", community.IDString()),
|
||||
zap.String("verifiedOwner", common.PubkeyToHex(verifiedOwner)),
|
||||
zap.String("signer", common.PubkeyToHex(signer)),
|
||||
zap.String("controlNode", common.PubkeyToHex(community.ControlNode())),
|
||||
)
|
||||
|
||||
// If we are not the verified owner anymore, drop the private key
|
||||
if !common.IsPubKeyEqual(verifiedOwner, &m.identity.PublicKey) {
|
||||
|
|
|
@ -331,7 +331,8 @@ func advertiseCommunityTo(s *suite.Suite, community *communities.Community, owne
|
|||
messageState := user.buildMessageState()
|
||||
messageState.CurrentMessageState = &CurrentMessageState{}
|
||||
messageState.CurrentMessageState.PublicKey = &user.identity.PublicKey
|
||||
err = user.handleCommunityDescription(messageState, signer, description, wrappedCommunity, nil)
|
||||
// TODO: handle shards?
|
||||
err = user.handleCommunityDescription(messageState, signer, description, wrappedCommunity, nil, nil)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/zap"
|
||||
|
||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
hexutil "github.com/ethereum/go-ethereum/common/hexutil"
|
||||
|
||||
utils "github.com/status-im/status-go/common"
|
||||
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
|
@ -581,3 +585,159 @@ func (s *MessengerCommunitiesSignersSuite) TestNewOwnerAcceptRequestToJoin() {
|
|||
s.joinCommunity(s.alice, community, s.bob)
|
||||
|
||||
}
|
||||
|
||||
func (s *MessengerCommunitiesSignersSuite) testDescriptionSignature(description []byte) {
|
||||
var amm protobuf.ApplicationMetadataMessage
|
||||
err := proto.Unmarshal(description, &amm)
|
||||
s.Require().NoError(err)
|
||||
|
||||
signer, err := utils.RecoverKey(&amm)
|
||||
s.Require().NoError(err)
|
||||
s.NotNil(signer)
|
||||
}
|
||||
|
||||
func (s *MessengerCommunitiesSignersSuite) forceCommunityChange(community *communities.Community, owner *Messenger, user *Messenger) {
|
||||
newDescription := community.DescriptionText() + " new"
|
||||
_, err := owner.EditCommunity(&requests.EditCommunity{
|
||||
CommunityID: community.ID(),
|
||||
CreateCommunity: requests.CreateCommunity{
|
||||
Membership: protobuf.CommunityPermissions_AUTO_ACCEPT,
|
||||
Name: community.Name(),
|
||||
Color: community.Color(),
|
||||
Description: newDescription,
|
||||
},
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
|
||||
// alice receives new description
|
||||
_, err = WaitOnMessengerResponse(user, func(r *MessengerResponse) bool {
|
||||
return len(r.Communities()) > 0 && r.Communities()[0].DescriptionText() == newDescription
|
||||
}, "new description not received")
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
func (s *MessengerCommunitiesSignersSuite) testSyncCommunity(mintOwnerToken bool) {
|
||||
|
||||
community := s.createCommunity(s.john)
|
||||
s.advertiseCommunityTo(s.john, community, s.alice)
|
||||
s.joinCommunity(s.john, community, s.alice)
|
||||
|
||||
// FIXME: Remove this workaround when fixed:
|
||||
// https://github.com/status-im/status-go/issues/4413
|
||||
s.forceCommunityChange(community, s.john, s.alice)
|
||||
|
||||
aliceCommunity, err := s.alice.GetCommunityByID(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.testDescriptionSignature(aliceCommunity.DescriptionProtocolMessage())
|
||||
|
||||
if mintOwnerToken {
|
||||
// john mints owner token
|
||||
var chainID uint64 = 1
|
||||
tokenAddress := "token-address"
|
||||
tokenName := "tokenName"
|
||||
tokenSymbol := "TSM"
|
||||
_, err := s.john.SaveCommunityToken(&token.CommunityToken{
|
||||
TokenType: protobuf.CommunityTokenType_ERC721,
|
||||
CommunityID: community.IDString(),
|
||||
Address: tokenAddress,
|
||||
ChainID: int(chainID),
|
||||
Name: tokenName,
|
||||
Supply: &bigint.BigInt{},
|
||||
Symbol: tokenSymbol,
|
||||
PrivilegesLevel: token.OwnerLevel,
|
||||
}, nil)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// john adds minted owner token to community
|
||||
err = s.john.AddCommunityToken(community.IDString(), int(chainID), tokenAddress)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// update mock - the signer for the community returned by the contracts should be john
|
||||
s.collectiblesServiceMock.SetSignerPubkeyForCommunity(community.ID(), common.PubkeyToHex(&s.john.identity.PublicKey))
|
||||
s.collectiblesServiceMock.SetMockCollectibleContractData(chainID, tokenAddress,
|
||||
&communitytokens.CollectibleContractData{TotalSupply: &bigint.BigInt{}})
|
||||
|
||||
// alice accepts community update
|
||||
_, err = WaitOnSignaledMessengerResponse(
|
||||
s.alice,
|
||||
func(r *MessengerResponse) bool {
|
||||
return len(r.Communities()) > 0 && len(r.Communities()[0].TokenPermissions()) == 1
|
||||
},
|
||||
"no communities",
|
||||
)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
|
||||
// Create alice second instance
|
||||
alice2, err := newMessengerWithKey(
|
||||
s.shh,
|
||||
s.alice.identity,
|
||||
s.logger.With(zap.String("name", "alice-2")),
|
||||
nil)
|
||||
|
||||
s.Require().NoError(err)
|
||||
|
||||
_, err = alice2.Start()
|
||||
s.Require().NoError(err)
|
||||
defer alice2.Shutdown() // nolint: errcheck
|
||||
|
||||
// Create communities backup
|
||||
|
||||
clock, _ := s.alice.getLastClockWithRelatedChat()
|
||||
communitiesBackup, err := s.alice.backupCommunities(context.Background(), clock)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// Find wanted communities in the backup
|
||||
|
||||
var syncCommunityMessages []*protobuf.SyncInstallationCommunity
|
||||
|
||||
for _, b := range communitiesBackup {
|
||||
for _, c := range b.Communities {
|
||||
if bytes.Equal(c.Id, community.ID()) {
|
||||
syncCommunityMessages = append(syncCommunityMessages, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.Require().Len(syncCommunityMessages, 1)
|
||||
|
||||
s.testDescriptionSignature(syncCommunityMessages[0].Description)
|
||||
|
||||
// Push the backup into second instance
|
||||
|
||||
messageState := alice2.buildMessageState()
|
||||
err = alice2.HandleSyncInstallationCommunity(messageState, syncCommunityMessages[0], nil)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(messageState.Response.Communities(), 1)
|
||||
|
||||
expectedControlNode := community.PublicKey()
|
||||
if mintOwnerToken {
|
||||
expectedControlNode = &s.john.identity.PublicKey
|
||||
}
|
||||
|
||||
responseCommunity := messageState.Response.Communities()[0]
|
||||
s.Require().Equal(community.IDString(), responseCommunity.IDString())
|
||||
s.Require().True(common.IsPubKeyEqual(expectedControlNode, responseCommunity.ControlNode()))
|
||||
}
|
||||
|
||||
func (s *MessengerCommunitiesSignersSuite) TestSyncTokenGatedCommunity() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
mintOwnerToken bool
|
||||
}{
|
||||
{
|
||||
name: "general community sync",
|
||||
mintOwnerToken: false,
|
||||
},
|
||||
{
|
||||
name: "community with token ownership",
|
||||
mintOwnerToken: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
s.testSyncCommunity(tc.mintOwnerToken)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
|
||||
"go.uber.org/zap"
|
||||
|
||||
utils "github.com/status-im/status-go/common"
|
||||
|
||||
"github.com/status-im/status-go/account"
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
|
@ -2603,8 +2605,8 @@ func (m *Messenger) passStoredCommunityInfoToSignalHandler(community *communitie
|
|||
}
|
||||
|
||||
// handleCommunityDescription handles an community description
|
||||
func (m *Messenger) handleCommunityDescription(state *ReceivedMessageState, signer *ecdsa.PublicKey, description *protobuf.CommunityDescription, rawPayload []byte, shard *protobuf.Shard) error {
|
||||
communityResponse, err := m.communitiesManager.HandleCommunityDescriptionMessage(signer, description, rawPayload, nil, shard)
|
||||
func (m *Messenger) handleCommunityDescription(state *ReceivedMessageState, signer *ecdsa.PublicKey, description *protobuf.CommunityDescription, rawPayload []byte, verifiedOwner *ecdsa.PublicKey, shard *protobuf.Shard) error {
|
||||
communityResponse, err := m.communitiesManager.HandleCommunityDescriptionMessage(signer, description, rawPayload, verifiedOwner, shard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -2945,7 +2947,7 @@ func (m *Messenger) HandleSyncInstallationCommunity(messageState *ReceivedMessag
|
|||
}
|
||||
|
||||
func (m *Messenger) handleSyncInstallationCommunity(messageState *ReceivedMessageState, syncCommunity *protobuf.SyncInstallationCommunity, statusMessage *v1protocol.StatusMessage) error {
|
||||
logger := m.logger.Named("handleSyncCommunity")
|
||||
logger := m.logger.Named("handleSyncInstallationCommunity")
|
||||
|
||||
// Should handle community
|
||||
shouldHandle, err := m.communitiesManager.ShouldHandleSyncCommunity(syncCommunity)
|
||||
|
@ -3008,8 +3010,17 @@ func (m *Messenger) handleSyncInstallationCommunity(messageState *ReceivedMessag
|
|||
return err
|
||||
}
|
||||
|
||||
// This is our own message, so we can trust the set community owner
|
||||
// This is good to do so that we don't have to queue all the actions done after the handled community description.
|
||||
// `signer` is `communityID` for a community with no owner token and `owner public key` otherwise
|
||||
signer, err := utils.RecoverKey(&amm)
|
||||
if err != nil {
|
||||
logger.Debug("failed to recover community description signer", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: handle shard
|
||||
err = m.handleCommunityDescription(messageState, orgPubKey, &cd, syncCommunity.Description, nil)
|
||||
err = m.handleCommunityDescription(messageState, signer, &cd, syncCommunity.Description, signer, nil)
|
||||
if err != nil {
|
||||
logger.Debug("m.handleCommunityDescription error", zap.Error(err))
|
||||
return err
|
||||
|
@ -3031,22 +3042,6 @@ func (m *Messenger) handleSyncInstallationCommunity(messageState *ReceivedMessag
|
|||
}
|
||||
}
|
||||
|
||||
savedCommunity, err := m.communitiesManager.GetByID(syncCommunity.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: if the community is token gated, it will be validated asynchronously
|
||||
// syncing needs to be adjusted in this case
|
||||
if savedCommunity == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := m.handleCommunityTokensMetadataByPrivilegedMembers(savedCommunity); err != nil {
|
||||
logger.Debug("m.handleCommunityTokensMetadataByPrivilegedMembers", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// if we are not waiting for approval, join or leave the community
|
||||
if !pending {
|
||||
var mr *MessengerResponse
|
||||
|
@ -3102,10 +3097,6 @@ func (m *Messenger) HandleSyncCommunitySettings(messageState *ReceivedMessageSta
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *Messenger) handleCommunityTokensMetadataByPrivilegedMembers(community *communities.Community) error {
|
||||
return m.communitiesManager.HandleCommunityTokensMetadataByPrivilegedMembers(community)
|
||||
}
|
||||
|
||||
func (m *Messenger) InitHistoryArchiveTasks(communities []*communities.Community) {
|
||||
|
||||
m.communitiesManager.LogStdout("initializing history archive tasks")
|
||||
|
|
|
@ -2324,7 +2324,7 @@ func (m *Messenger) handleChatMessage(state *ReceivedMessageState, forceSeen boo
|
|||
return err
|
||||
}
|
||||
|
||||
err = m.handleCommunityDescription(state, signer, description, receivedMessage.GetCommunity(), receivedMessage.GetShard())
|
||||
err = m.handleCommunityDescription(state, signer, description, receivedMessage.GetCommunity(), nil, receivedMessage.GetShard())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -3667,7 +3667,7 @@ func (m *Messenger) HandlePushNotificationRequest(state *ReceivedMessageState, m
|
|||
|
||||
func (m *Messenger) HandleCommunityDescription(state *ReceivedMessageState, message *protobuf.CommunityDescription, statusMessage *v1protocol.StatusMessage) error {
|
||||
// TODO: handle shard
|
||||
err := m.handleCommunityDescription(state, state.CurrentMessageState.PublicKey, message, statusMessage.EncryptionLayer.Payload, nil)
|
||||
err := m.handleCommunityDescription(state, state.CurrentMessageState.PublicKey, message, statusMessage.EncryptionLayer.Payload, nil, nil)
|
||||
if err != nil {
|
||||
m.logger.Warn("failed to handle CommunityDescription", zap.Error(err))
|
||||
return err
|
||||
|
|
Loading…
Reference in New Issue