chore: check and manualy verify community if during the fetchCommunity, community was added to the verification loop (#4533)
This commit is contained in:
parent
7814f39cd7
commit
5c704b2ec2
|
@ -435,65 +435,82 @@ func (m *Manager) runOwnerVerificationLoop() {
|
|||
for id, communities := range communitiesToValidate {
|
||||
m.logger.Info("validating communities", zap.String("id", id), zap.Int("count", len(communities)))
|
||||
|
||||
for _, communityToValidate := range communities {
|
||||
signer, description, err := UnwrapCommunityDescriptionMessage(communityToValidate.payload)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to unwrap community", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
chainID := CommunityDescriptionTokenOwnerChainID(description)
|
||||
if chainID == 0 {
|
||||
// This should not happen
|
||||
m.logger.Error("chain id is 0, ignoring")
|
||||
continue
|
||||
}
|
||||
|
||||
m.logger.Info("validating community", zap.String("id", types.EncodeHex(communityToValidate.id)), zap.String("signer", common.PubkeyToHex(signer)))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
|
||||
owner, err := m.ownerVerifier.SafeGetSignerPubKey(ctx, chainID, id)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to get owner", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
ownerPK, err := common.HexToPubkey(owner)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to convert pk string to ecdsa", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: handle shards
|
||||
response, err := m.HandleCommunityDescriptionMessage(signer, description, communityToValidate.payload, ownerPK, nil)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to handle community", zap.Error(err))
|
||||
err = m.persistence.DeleteCommunityToValidate(communityToValidate.id, communityToValidate.clock)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to delete community to validate", zap.Error(err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
|
||||
m.logger.Info("community validated", zap.String("id", types.EncodeHex(communityToValidate.id)), zap.String("signer", common.PubkeyToHex(signer)))
|
||||
m.publish(&Subscription{TokenCommunityValidated: response})
|
||||
err := m.persistence.DeleteCommunitiesToValidateByCommunityID(communityToValidate.id)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to delete communities to validate", zap.Error(err))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
_, _ = m.validateCommunity(communities)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *Manager) ValidateCommunityByID(communityID types.HexBytes) (*CommunityResponse, error) {
|
||||
communityToValidate, err := m.persistence.getCommunityToValidateByID(communityID)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to validate community by ID", zap.String("id", communityID.String()), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m.validateCommunity(communityToValidate)
|
||||
|
||||
}
|
||||
|
||||
func (m *Manager) validateCommunity(communityToValidateData []communityToValidate) (*CommunityResponse, error) {
|
||||
for _, communityToValidate := range communityToValidateData {
|
||||
signer, description, err := UnwrapCommunityDescriptionMessage(communityToValidate.payload)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to unwrap community", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
chainID := CommunityDescriptionTokenOwnerChainID(description)
|
||||
if chainID == 0 {
|
||||
// This should not happen
|
||||
m.logger.Error("chain id is 0, ignoring")
|
||||
continue
|
||||
}
|
||||
|
||||
m.logger.Info("validating community", zap.String("id", types.EncodeHex(communityToValidate.id)), zap.String("signer", common.PubkeyToHex(signer)))
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
|
||||
owner, err := m.ownerVerifier.SafeGetSignerPubKey(ctx, chainID, types.EncodeHex(communityToValidate.id))
|
||||
if err != nil {
|
||||
m.logger.Error("failed to get owner", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
ownerPK, err := common.HexToPubkey(owner)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to convert pk string to ecdsa", zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: handle shards
|
||||
response, err := m.HandleCommunityDescriptionMessage(signer, description, communityToValidate.payload, ownerPK, nil)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to handle community", zap.Error(err))
|
||||
err = m.persistence.DeleteCommunityToValidate(communityToValidate.id, communityToValidate.clock)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to delete community to validate", zap.Error(err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
|
||||
m.logger.Info("community validated", zap.String("id", types.EncodeHex(communityToValidate.id)), zap.String("signer", common.PubkeyToHex(signer)))
|
||||
m.publish(&Subscription{TokenCommunityValidated: response})
|
||||
err := m.persistence.DeleteCommunitiesToValidateByCommunityID(communityToValidate.id)
|
||||
if err != nil {
|
||||
m.logger.Error("failed to delete communities to validate", zap.Error(err))
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *Manager) Stop() error {
|
||||
m.stopped = true
|
||||
close(m.quit)
|
||||
|
|
|
@ -1489,6 +1489,30 @@ func (p *Persistence) getCommunitiesToValidate() (map[string][]communityToValida
|
|||
|
||||
}
|
||||
|
||||
func (p *Persistence) getCommunityToValidateByID(communityID types.HexBytes) ([]communityToValidate, error) {
|
||||
communityToValidateArray := []communityToValidate{}
|
||||
rows, err := p.db.Query(`SELECT id, clock, payload, signer FROM communities_validate_signer WHERE id = ? AND validate_at <= ? ORDER BY clock DESC`, communityID, time.Now().UnixNano())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
communityToValidate := communityToValidate{}
|
||||
err := rows.Scan(&communityToValidate.id, &communityToValidate.clock, &communityToValidate.payload, &communityToValidate.signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
communityToValidateArray = append(communityToValidateArray, communityToValidate)
|
||||
}
|
||||
|
||||
return communityToValidateArray, nil
|
||||
|
||||
}
|
||||
|
||||
func (p *Persistence) DeleteCommunitiesToValidateByCommunityID(communityID []byte) error {
|
||||
_, err := p.db.Exec(`DELETE FROM communities_validate_signer WHERE id = ?`, communityID)
|
||||
return err
|
||||
|
|
|
@ -913,3 +913,11 @@ func (s *PersistenceSuite) TestSaveShardInfo() {
|
|||
s.Require().Error(err, sql.ErrNoRows)
|
||||
s.Require().Nil(resultShard)
|
||||
}
|
||||
|
||||
func (s *PersistenceSuite) TestGetCommunityToValidateByID() {
|
||||
communityID := types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
result, err := s.db.getCommunityToValidateByID(communityID)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(result, 0)
|
||||
}
|
||||
|
|
|
@ -373,15 +373,40 @@ func (r *storeNodeRequest) shouldFetchNextPage(envelopesCount int) (bool, uint32
|
|||
// Try to get community from database
|
||||
switch r.requestID.RequestType {
|
||||
case storeNodeCommunityRequest:
|
||||
community, err := r.manager.messenger.communitiesManager.GetByIDString(r.requestID.DataID)
|
||||
|
||||
communityID, err := types.DecodeHex(r.requestID.DataID)
|
||||
if err != nil {
|
||||
logger.Error("failed to read from database",
|
||||
logger.Error("failed to decode community ID",
|
||||
zap.String("communityID", r.requestID.DataID),
|
||||
zap.Error(err))
|
||||
r.result = storeNodeRequestResult{
|
||||
community: nil,
|
||||
err: fmt.Errorf("failed to read from database: %w", err),
|
||||
err: fmt.Errorf("failed to decode community ID: %w", err),
|
||||
}
|
||||
return false, 0 // failed to decode community ID, no sense to continue the procedure
|
||||
}
|
||||
|
||||
// check if community is waiting for a verification and do a verification manually
|
||||
_, err = r.manager.messenger.communitiesManager.ValidateCommunityByID(communityID)
|
||||
if err != nil {
|
||||
logger.Error("failed to validate community by ID",
|
||||
zap.String("communityID", r.requestID.DataID),
|
||||
zap.Error(err))
|
||||
r.result = storeNodeRequestResult{
|
||||
community: nil,
|
||||
err: fmt.Errorf("failed to validate community by ID: %w", err),
|
||||
}
|
||||
return false, 0 // failed to validate community, no sense to continue the procedure
|
||||
}
|
||||
|
||||
community, err := r.manager.messenger.communitiesManager.GetByID(communityID)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("failed to read community from database",
|
||||
zap.String("communityID", r.requestID.DataID),
|
||||
zap.Error(err))
|
||||
r.result = storeNodeRequestResult{
|
||||
community: nil,
|
||||
err: fmt.Errorf("failed to read community from database: %w", err),
|
||||
}
|
||||
return false, 0 // failed to read from database, no sense to continue the procedure
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/status-im/status-go/protocol/communities/token"
|
||||
"github.com/status-im/status-go/protocol/transport"
|
||||
|
||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||
|
@ -29,7 +30,9 @@ import (
|
|||
"github.com/status-im/status-go/protocol/requests"
|
||||
"github.com/status-im/status-go/t/helpers"
|
||||
|
||||
"github.com/status-im/status-go/services/communitytokens"
|
||||
mailserversDB "github.com/status-im/status-go/services/mailservers"
|
||||
"github.com/status-im/status-go/services/wallet/bigint"
|
||||
waku2 "github.com/status-im/status-go/wakuv2"
|
||||
wakuV2common "github.com/status-im/status-go/wakuv2/common"
|
||||
)
|
||||
|
@ -59,6 +62,8 @@ type MessengerStoreNodeRequestSuite struct {
|
|||
ownerWaku types.Waku
|
||||
bobWaku types.Waku
|
||||
|
||||
collectiblesServiceMock *CollectiblesServiceMock
|
||||
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
|
@ -121,6 +126,8 @@ func (s *MessengerStoreNodeRequestSuite) SetupTest() {
|
|||
|
||||
s.storeNodeAddress = storeNodeListenAddresses[0]
|
||||
s.logger.Info("store node ready", zap.String("address", s.storeNodeAddress))
|
||||
|
||||
s.collectiblesServiceMock = &CollectiblesServiceMock{}
|
||||
}
|
||||
|
||||
func (s *MessengerStoreNodeRequestSuite) TearDown() {
|
||||
|
@ -173,6 +180,7 @@ func (s *MessengerStoreNodeRequestSuite) newMessenger(shh types.Waku, logger *za
|
|||
WithClusterConfig(params.ClusterConfig{
|
||||
Fleet: localFleet,
|
||||
}),
|
||||
WithCommunityTokensService(s.collectiblesServiceMock),
|
||||
}
|
||||
|
||||
messenger, err := newMessengerWithKey(shh, privateKey, logger, options)
|
||||
|
@ -217,6 +225,8 @@ func (s *MessengerStoreNodeRequestSuite) requireCommunitiesEqual(c *communities.
|
|||
s.Require().Equal(expected.Color(), c.Color())
|
||||
s.Require().Equal(expected.Tags(), c.Tags())
|
||||
s.Require().Equal(expected.Shard(), c.Shard())
|
||||
s.Require().Equal(expected.TokenPermissions(), c.TokenPermissions())
|
||||
s.Require().Equal(expected.CommunityTokensMetadata(), c.CommunityTokensMetadata())
|
||||
}
|
||||
|
||||
func (s *MessengerStoreNodeRequestSuite) requireContactsEqual(c *Contact, expected *Contact) {
|
||||
|
@ -818,3 +828,45 @@ func (s *MessengerStoreNodeRequestSuite) TestFetchRealCommunity() {
|
|||
fmt.Printf("%s --- %s\n", storeNodeName, result.toString())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *MessengerStoreNodeRequestSuite) TestFetchingCommunityWithOwnerToken() {
|
||||
s.createOwner()
|
||||
s.createBob()
|
||||
|
||||
s.waitForAvailableStoreNode(s.owner)
|
||||
community := s.createCommunity(s.owner)
|
||||
|
||||
// owner mints owner token
|
||||
var chainID uint64 = 1
|
||||
tokenAddress := "token-address"
|
||||
tokenName := "tokenName"
|
||||
tokenSymbol := "TSM"
|
||||
_, err := s.owner.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)
|
||||
|
||||
// owner adds minted owner token to community
|
||||
err = s.owner.AddCommunityToken(community.IDString(), int(chainID), tokenAddress)
|
||||
s.Require().NoError(err)
|
||||
|
||||
// update mock - the signer for the community returned by the contracts should be owner
|
||||
s.collectiblesServiceMock.SetSignerPubkeyForCommunity(community.ID(), common.PubkeyToHex(&s.owner.identity.PublicKey))
|
||||
s.collectiblesServiceMock.SetMockCollectibleContractData(chainID, tokenAddress,
|
||||
&communitytokens.CollectibleContractData{TotalSupply: &bigint.BigInt{}})
|
||||
|
||||
community, err = s.owner.communitiesManager.GetByID(community.ID())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(community.TokenPermissions(), 1)
|
||||
|
||||
s.waitForAvailableStoreNode(s.bob)
|
||||
|
||||
s.fetchCommunity(s.bob, community.CommunityShard(), community)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue