github.com/status-im/status-go@v1.1.0/protocol/communities/manager_test.go (about)

     1  package communities
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"image"
     8  	"image/png"
     9  	"math"
    10  	"math/big"
    11  	"os"
    12  	"testing"
    13  	"time"
    14  
    15  	gethcommon "github.com/ethereum/go-ethereum/common"
    16  	"github.com/ethereum/go-ethereum/common/hexutil"
    17  	"github.com/status-im/status-go/appdatabase"
    18  	"github.com/status-im/status-go/eth-node/crypto"
    19  	"github.com/status-im/status-go/eth-node/types"
    20  	userimages "github.com/status-im/status-go/images"
    21  	"github.com/status-im/status-go/params"
    22  	"github.com/status-im/status-go/protocol/common"
    23  	community_token "github.com/status-im/status-go/protocol/communities/token"
    24  	"github.com/status-im/status-go/protocol/protobuf"
    25  	"github.com/status-im/status-go/protocol/requests"
    26  	"github.com/status-im/status-go/protocol/sqlite"
    27  	"github.com/status-im/status-go/protocol/transport"
    28  	v1 "github.com/status-im/status-go/protocol/v1"
    29  	"github.com/status-im/status-go/services/wallet/bigint"
    30  	walletCommon "github.com/status-im/status-go/services/wallet/common"
    31  	"github.com/status-im/status-go/services/wallet/thirdparty"
    32  	"github.com/status-im/status-go/services/wallet/token"
    33  	"github.com/status-im/status-go/t/helpers"
    34  
    35  	"github.com/golang/protobuf/proto"
    36  	_ "github.com/mutecomm/go-sqlcipher/v4" // require go-sqlcipher that overrides default implementation
    37  	"github.com/stretchr/testify/suite"
    38  	"go.uber.org/zap"
    39  )
    40  
    41  func TestManagerSuite(t *testing.T) {
    42  	suite.Run(t, new(ManagerSuite))
    43  }
    44  
    45  type ManagerSuite struct {
    46  	suite.Suite
    47  	manager        *Manager
    48  	archiveManager *ArchiveManager
    49  }
    50  
    51  func (s *ManagerSuite) buildManagers(ownerVerifier OwnerVerifier) (*Manager, *ArchiveManager) {
    52  	db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
    53  	s.Require().NoError(err, "creating sqlite db instance")
    54  	err = sqlite.Migrate(db)
    55  	s.Require().NoError(err, "protocol migrate")
    56  
    57  	key, err := crypto.GenerateKey()
    58  	s.Require().NoError(err)
    59  
    60  	logger, err := zap.NewDevelopment()
    61  	s.Require().NoError(err)
    62  
    63  	m, err := NewManager(key, "", db, nil, logger, nil, ownerVerifier, nil, &TimeSourceStub{}, nil, nil)
    64  	s.Require().NoError(err)
    65  	s.Require().NoError(m.Start())
    66  
    67  	amc := &ArchiveManagerConfig{
    68  		TorrentConfig: buildTorrentConfig(),
    69  		Logger:        logger,
    70  		Persistence:   m.GetPersistence(),
    71  		Transport:     nil,
    72  		Identity:      key,
    73  		Encryptor:     nil,
    74  		Publisher:     m,
    75  	}
    76  	t := NewArchiveManager(amc)
    77  	s.Require().NoError(err)
    78  
    79  	return m, t
    80  }
    81  
    82  func (s *ManagerSuite) SetupTest() {
    83  	m, t := s.buildManagers(nil)
    84  	SetValidateInterval(30 * time.Millisecond)
    85  	s.manager = m
    86  	s.archiveManager = t
    87  }
    88  
    89  func intToBig(n int64) *hexutil.Big {
    90  	return (*hexutil.Big)(big.NewInt(n))
    91  }
    92  
    93  func uintToDecBig(n uint64) *bigint.BigInt {
    94  	return &bigint.BigInt{Int: big.NewInt(int64(n))}
    95  }
    96  
    97  func tokenBalance(tokenID uint64, balance uint64) thirdparty.TokenBalance {
    98  	return thirdparty.TokenBalance{
    99  		TokenID: uintToDecBig(tokenID),
   100  		Balance: uintToDecBig(balance),
   101  	}
   102  }
   103  
   104  func (s *ManagerSuite) getHistoryTasksCount() int {
   105  	// sync.Map doesn't have a Len function, so we need to count manually
   106  	count := 0
   107  	s.archiveManager.historyArchiveTasks.Range(func(_, _ interface{}) bool {
   108  		count++
   109  		return true
   110  	})
   111  	return count
   112  }
   113  
   114  type testCollectiblesManager struct {
   115  	response map[uint64]map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress
   116  }
   117  
   118  func (m *testCollectiblesManager) setResponse(chainID uint64, walletAddress gethcommon.Address, contractAddress gethcommon.Address, balances []thirdparty.TokenBalance) {
   119  	if m.response == nil {
   120  		m.response = make(map[uint64]map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
   121  	}
   122  	if m.response[chainID] == nil {
   123  		m.response[chainID] = make(map[gethcommon.Address]thirdparty.TokenBalancesPerContractAddress)
   124  	}
   125  	if m.response[chainID][walletAddress] == nil {
   126  		m.response[chainID][walletAddress] = make(thirdparty.TokenBalancesPerContractAddress)
   127  	}
   128  
   129  	m.response[chainID][walletAddress][contractAddress] = balances
   130  }
   131  
   132  func (m *testCollectiblesManager) FetchBalancesByOwnerAndContractAddress(ctx context.Context, chainID walletCommon.ChainID, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error) {
   133  	return m.response[uint64(chainID)][ownerAddress], nil
   134  }
   135  
   136  func (m *testCollectiblesManager) GetCollectibleOwnership(id thirdparty.CollectibleUniqueID) ([]thirdparty.AccountBalance, error) {
   137  	return nil, errors.New("GetCollectibleOwnership is not implemented for testCollectiblesManager")
   138  }
   139  
   140  func (m *testCollectiblesManager) FetchCollectibleOwnersByContractAddress(ctx context.Context, chainID walletCommon.ChainID, contractAddress gethcommon.Address) (*thirdparty.CollectibleContractOwnership, error) {
   141  	ret := &thirdparty.CollectibleContractOwnership{
   142  		ContractAddress: contractAddress,
   143  		Owners:          []thirdparty.CollectibleOwner{},
   144  	}
   145  
   146  	balancesPerOwner, ok := m.response[uint64(chainID)]
   147  	if !ok {
   148  		return ret, nil
   149  	}
   150  
   151  	for ownerAddress, collectibles := range balancesPerOwner {
   152  		for collectibleAddress, balances := range collectibles {
   153  			if collectibleAddress == contractAddress {
   154  				ret.Owners = append(ret.Owners, thirdparty.CollectibleOwner{
   155  					OwnerAddress:  ownerAddress,
   156  					TokenBalances: balances,
   157  				})
   158  				break
   159  			}
   160  		}
   161  	}
   162  
   163  	return ret, nil
   164  }
   165  
   166  func (m *testCollectiblesManager) FetchCachedBalancesByOwnerAndContractAddress(ctx context.Context, chainID walletCommon.ChainID, ownerAddress gethcommon.Address, contractAddresses []gethcommon.Address) (thirdparty.TokenBalancesPerContractAddress, error) {
   167  	return m.response[uint64(chainID)][ownerAddress], nil
   168  }
   169  
   170  type testTokenManager struct {
   171  	response map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big
   172  }
   173  
   174  func (m *testTokenManager) setResponse(chainID uint64, walletAddress, tokenAddress gethcommon.Address, balance int64) {
   175  
   176  	if m.response == nil {
   177  		m.response = make(map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
   178  	}
   179  
   180  	if m.response[chainID] == nil {
   181  		m.response[chainID] = make(map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big)
   182  	}
   183  
   184  	if m.response[chainID][walletAddress] == nil {
   185  		m.response[chainID][walletAddress] = make(map[gethcommon.Address]*hexutil.Big)
   186  	}
   187  
   188  	m.response[chainID][walletAddress][tokenAddress] = intToBig(balance)
   189  
   190  }
   191  
   192  func (m *testTokenManager) GetAllChainIDs() ([]uint64, error) {
   193  	return []uint64{5}, nil
   194  }
   195  
   196  func (m *testTokenManager) GetBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big, error) {
   197  	return m.response, nil
   198  }
   199  
   200  func (m *testTokenManager) GetCachedBalancesByChain(ctx context.Context, accounts, tokenAddresses []gethcommon.Address, chainIDs []uint64) (BalancesByChain, error) {
   201  	return m.response, nil
   202  }
   203  
   204  func (m *testTokenManager) FindOrCreateTokenByAddress(ctx context.Context, chainID uint64, address gethcommon.Address) *token.Token {
   205  	return nil
   206  }
   207  
   208  func (s *ManagerSuite) setupManagerForTokenPermissions() (*Manager, *testCollectiblesManager, *testTokenManager) {
   209  	db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
   210  	s.NoError(err, "creating sqlite db instance")
   211  	err = sqlite.Migrate(db)
   212  	s.NoError(err, "protocol migrate")
   213  
   214  	key, err := crypto.GenerateKey()
   215  	s.Require().NoError(err)
   216  	s.Require().NoError(err)
   217  
   218  	cm := &testCollectiblesManager{}
   219  	tm := &testTokenManager{}
   220  
   221  	options := []ManagerOption{
   222  		WithWalletConfig(&params.WalletConfig{
   223  			OpenseaAPIKey: "some-key",
   224  		}),
   225  		WithCollectiblesManager(cm),
   226  		WithTokenManager(tm),
   227  	}
   228  
   229  	m, err := NewManager(key, "", db, nil, nil, nil, nil, nil, &TimeSourceStub{}, nil, nil, options...)
   230  	s.Require().NoError(err)
   231  	s.Require().NoError(m.Start())
   232  
   233  	return m, cm, tm
   234  }
   235  
   236  func (s *ManagerSuite) TestRetrieveTokens() {
   237  	m, _, tm := s.setupManagerForTokenPermissions()
   238  
   239  	var chainID uint64 = 5
   240  	contractAddresses := make(map[uint64]string)
   241  	contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
   242  	var decimals uint64 = 18
   243  
   244  	var tokenCriteria = []*protobuf.TokenCriteria{
   245  		&protobuf.TokenCriteria{
   246  			ContractAddresses: contractAddresses,
   247  			Symbol:            "STT",
   248  			Type:              protobuf.CommunityTokenType_ERC20,
   249  			Name:              "Status Test Token",
   250  			AmountInWei:       "1000000000000000000",
   251  			Decimals:          decimals,
   252  		},
   253  	}
   254  
   255  	var permissions = []*CommunityTokenPermission{
   256  		&CommunityTokenPermission{
   257  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   258  				Id:            "some-id",
   259  				Type:          protobuf.CommunityTokenPermission_BECOME_MEMBER,
   260  				TokenCriteria: tokenCriteria,
   261  			},
   262  		},
   263  	}
   264  
   265  	preParsedPermissions := preParsedCommunityPermissionsData(permissions)
   266  
   267  	accountChainIDsCombination := []*AccountChainIDsCombination{
   268  		&AccountChainIDsCombination{
   269  			Address:  gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
   270  			ChainIDs: []uint64{chainID},
   271  		},
   272  	}
   273  	// Set response to exactly the right one
   274  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
   275  	resp, err := m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false)
   276  	s.Require().NoError(err)
   277  	s.Require().NotNil(resp)
   278  	s.Require().True(resp.Satisfied)
   279  
   280  	// Set response to 0
   281  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
   282  	resp, err = m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false)
   283  	s.Require().NoError(err)
   284  	s.Require().NotNil(resp)
   285  	s.Require().False(resp.Satisfied)
   286  }
   287  
   288  func (s *ManagerSuite) TestRetrieveCollectibles() {
   289  	m, cm, _ := s.setupManagerForTokenPermissions()
   290  
   291  	var chainID uint64 = 5
   292  	contractAddresses := make(map[uint64]string)
   293  	contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
   294  
   295  	tokenID := uint64(10)
   296  	var tokenBalances []thirdparty.TokenBalance
   297  
   298  	var tokenCriteria = []*protobuf.TokenCriteria{
   299  		{
   300  			ContractAddresses: contractAddresses,
   301  			TokenIds:          []uint64{tokenID},
   302  			Type:              protobuf.CommunityTokenType_ERC721,
   303  			AmountInWei:       "1",
   304  		},
   305  	}
   306  
   307  	var permissions = []*CommunityTokenPermission{
   308  		{
   309  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   310  				Id:            "some-id",
   311  				Type:          protobuf.CommunityTokenPermission_BECOME_MEMBER,
   312  				TokenCriteria: tokenCriteria,
   313  			},
   314  		},
   315  	}
   316  
   317  	preParsedPermissions := preParsedCommunityPermissionsData(permissions)
   318  
   319  	accountChainIDsCombination := []*AccountChainIDsCombination{
   320  		{
   321  			Address:  gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
   322  			ChainIDs: []uint64{chainID},
   323  		},
   324  	}
   325  
   326  	// Set response to exactly the right one
   327  	tokenBalances = []thirdparty.TokenBalance{tokenBalance(tokenID, 1)}
   328  	cm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), tokenBalances)
   329  	resp, err := m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false)
   330  	s.Require().NoError(err)
   331  	s.Require().NotNil(resp)
   332  	s.Require().True(resp.Satisfied)
   333  
   334  	// Set balances to 0
   335  	tokenBalances = []thirdparty.TokenBalance{}
   336  	cm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), tokenBalances)
   337  	resp, err = m.PermissionChecker.CheckPermissions(preParsedPermissions, accountChainIDsCombination, false)
   338  	s.Require().NoError(err)
   339  	s.Require().NotNil(resp)
   340  	s.Require().False(resp.Satisfied)
   341  }
   342  
   343  func (s *ManagerSuite) TestCreateCommunity() {
   344  	request := &requests.CreateCommunity{
   345  		Name:        "status",
   346  		Description: "token membership description",
   347  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
   348  	}
   349  
   350  	community, err := s.manager.CreateCommunity(request, true)
   351  	s.Require().NoError(err)
   352  	s.Require().NotNil(community)
   353  
   354  	communities, err := s.manager.All()
   355  	s.Require().NoError(err)
   356  	s.Require().Len(communities, 1)
   357  
   358  	actualCommunity := communities[0]
   359  	if bytes.Equal(community.ID(), communities[0].ID()) {
   360  		actualCommunity = communities[0]
   361  	}
   362  
   363  	s.Require().Equal(community.ID(), actualCommunity.ID())
   364  	s.Require().Equal(community.PrivateKey(), actualCommunity.PrivateKey())
   365  	s.Require().True(community.IsControlNode())
   366  	s.Require().True(proto.Equal(community.config.CommunityDescription, actualCommunity.config.CommunityDescription))
   367  }
   368  
   369  func (s *ManagerSuite) TestCreateCommunity_WithBanner() {
   370  	// Generate test image bigger than BannerDim
   371  	testImage := image.NewRGBA(image.Rect(0, 0, 20, 10))
   372  
   373  	tmpTestFilePath := s.T().TempDir() + "/test.png"
   374  	file, err := os.Create(tmpTestFilePath)
   375  	s.NoError(err)
   376  	defer file.Close()
   377  
   378  	err = png.Encode(file, testImage)
   379  	s.Require().NoError(err)
   380  
   381  	request := &requests.CreateCommunity{
   382  		Name:        "with_banner",
   383  		Description: "community with banner ",
   384  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
   385  		Banner: userimages.CroppedImage{
   386  			ImagePath: tmpTestFilePath,
   387  			X:         1,
   388  			Y:         1,
   389  			Width:     10,
   390  			Height:    5,
   391  		},
   392  	}
   393  
   394  	community, err := s.manager.CreateCommunity(request, true)
   395  	s.Require().NoError(err)
   396  	s.Require().NotNil(community)
   397  
   398  	communities, err := s.manager.All()
   399  	s.Require().NoError(err)
   400  	s.Require().Len(communities, 1)
   401  	s.Require().Equal(len(community.config.CommunityDescription.Identity.Images), 1)
   402  	testIdentityImage, isMapContainsKey := community.config.CommunityDescription.Identity.Images[userimages.BannerIdentityName]
   403  	s.Require().True(isMapContainsKey)
   404  	s.Require().Positive(len(testIdentityImage.Payload))
   405  }
   406  
   407  func (s *ManagerSuite) TestEditCommunity() {
   408  	//create community
   409  	createRequest := &requests.CreateCommunity{
   410  		Name:        "status",
   411  		Description: "status community description",
   412  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
   413  	}
   414  
   415  	community, err := s.manager.CreateCommunity(createRequest, true)
   416  	s.Require().NoError(err)
   417  	s.Require().NotNil(community)
   418  
   419  	update := &requests.EditCommunity{
   420  		CommunityID: community.ID(),
   421  		CreateCommunity: requests.CreateCommunity{
   422  			Name:        "statusEdited",
   423  			Description: "status community description edited",
   424  		},
   425  	}
   426  
   427  	updatedCommunity, err := s.manager.EditCommunity(update)
   428  	s.Require().NoError(err)
   429  	s.Require().NotNil(updatedCommunity)
   430  
   431  	//ensure updated community successfully stored
   432  	communities, err := s.manager.All()
   433  	s.Require().NoError(err)
   434  	s.Require().Len(communities, 1)
   435  
   436  	storedCommunity := communities[0]
   437  	if bytes.Equal(community.ID(), communities[0].ID()) {
   438  		storedCommunity = communities[0]
   439  	}
   440  
   441  	s.Require().Equal(storedCommunity.ID(), updatedCommunity.ID())
   442  	s.Require().Equal(storedCommunity.PrivateKey(), updatedCommunity.PrivateKey())
   443  	s.Require().Equal(storedCommunity.config.CommunityDescription.Identity.DisplayName, update.CreateCommunity.Name)
   444  	s.Require().Equal(storedCommunity.config.CommunityDescription.Identity.Description, update.CreateCommunity.Description)
   445  }
   446  
   447  func (s *ManagerSuite) TestGetControlledCommunitiesChatIDs() {
   448  	community, _, err := s.buildCommunityWithChat()
   449  	s.Require().NoError(err)
   450  	s.Require().NotNil(community)
   451  
   452  	controlledChatIDs, err := s.manager.GetOwnedCommunitiesChatIDs()
   453  
   454  	s.Require().NoError(err)
   455  	s.Require().Len(controlledChatIDs, 1)
   456  }
   457  
   458  func (s *ManagerSuite) TestStartAndStopTorrentClient() {
   459  	err := s.archiveManager.StartTorrentClient()
   460  	s.Require().NoError(err)
   461  	s.Require().NotNil(s.archiveManager.torrentClient)
   462  	defer s.archiveManager.Stop() //nolint: errcheck
   463  
   464  	_, err = os.Stat(s.archiveManager.torrentConfig.DataDir)
   465  	s.Require().NoError(err)
   466  	s.Require().Equal(s.archiveManager.torrentClientStarted(), true)
   467  }
   468  
   469  func (s *ManagerSuite) TestStartHistoryArchiveTasksInterval() {
   470  	err := s.archiveManager.StartTorrentClient()
   471  	s.Require().NoError(err)
   472  	defer s.archiveManager.Stop() //nolint: errcheck
   473  
   474  	community, _, err := s.buildCommunityWithChat()
   475  	s.Require().NoError(err)
   476  
   477  	interval := 10 * time.Second
   478  	go s.archiveManager.StartHistoryArchiveTasksInterval(community, interval)
   479  	// Due to async exec we need to wait a bit until we check
   480  	// the task count.
   481  	time.Sleep(5 * time.Second)
   482  
   483  	count := s.getHistoryTasksCount()
   484  	s.Require().Equal(count, 1)
   485  
   486  	// We wait another 5 seconds to ensure the first tick has kicked in
   487  	time.Sleep(5 * time.Second)
   488  
   489  	_, err = os.Stat(torrentFile(s.archiveManager.torrentConfig.TorrentDir, community.IDString()))
   490  	s.Require().Error(err)
   491  
   492  	s.archiveManager.StopHistoryArchiveTasksInterval(community.ID())
   493  	s.archiveManager.historyArchiveTasksWaitGroup.Wait()
   494  	count = s.getHistoryTasksCount()
   495  	s.Require().Equal(count, 0)
   496  }
   497  
   498  func (s *ManagerSuite) TestStopHistoryArchiveTasksIntervals() {
   499  	err := s.archiveManager.StartTorrentClient()
   500  	s.Require().NoError(err)
   501  	defer s.archiveManager.Stop() //nolint: errcheck
   502  
   503  	community, _, err := s.buildCommunityWithChat()
   504  	s.Require().NoError(err)
   505  
   506  	interval := 10 * time.Second
   507  	go s.archiveManager.StartHistoryArchiveTasksInterval(community, interval)
   508  
   509  	time.Sleep(2 * time.Second)
   510  
   511  	count := s.getHistoryTasksCount()
   512  	s.Require().Equal(count, 1)
   513  
   514  	s.archiveManager.stopHistoryArchiveTasksIntervals()
   515  
   516  	count = s.getHistoryTasksCount()
   517  	s.Require().Equal(count, 0)
   518  }
   519  
   520  func (s *ManagerSuite) TestStopTorrentClient_ShouldStopHistoryArchiveTasks() {
   521  	err := s.archiveManager.StartTorrentClient()
   522  	s.Require().NoError(err)
   523  	defer s.archiveManager.Stop() //nolint: errcheck
   524  
   525  	community, _, err := s.buildCommunityWithChat()
   526  	s.Require().NoError(err)
   527  
   528  	interval := 10 * time.Second
   529  	go s.archiveManager.StartHistoryArchiveTasksInterval(community, interval)
   530  	// Due to async exec we need to wait a bit until we check
   531  	// the task count.
   532  	time.Sleep(2 * time.Second)
   533  
   534  	count := s.getHistoryTasksCount()
   535  	s.Require().Equal(count, 1)
   536  
   537  	err = s.archiveManager.Stop()
   538  	s.Require().NoError(err)
   539  
   540  	count = s.getHistoryTasksCount()
   541  	s.Require().Equal(count, 0)
   542  }
   543  
   544  func (s *ManagerSuite) TestStartTorrentClient_DelayedUntilOnline() {
   545  	s.Require().False(s.archiveManager.torrentClientStarted())
   546  
   547  	s.archiveManager.SetOnline(true)
   548  	s.Require().True(s.archiveManager.torrentClientStarted())
   549  }
   550  
   551  func (s *ManagerSuite) TestCreateHistoryArchiveTorrent_WithoutMessages() {
   552  	community, chatID, err := s.buildCommunityWithChat()
   553  	s.Require().NoError(err)
   554  
   555  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   556  	topics := []types.TopicType{topic}
   557  
   558  	// Time range of 7 days
   559  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   560  	endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   561  	// Partition of 7 days
   562  	partition := 7 * 24 * time.Hour
   563  
   564  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false)
   565  	s.Require().NoError(err)
   566  
   567  	// There are no waku messages in the database so we don't expect
   568  	// any archives to be created
   569  	_, err = os.Stat(s.archiveManager.archiveDataFile(community.IDString()))
   570  	s.Require().Error(err)
   571  	_, err = os.Stat(s.archiveManager.archiveIndexFile(community.IDString()))
   572  	s.Require().Error(err)
   573  	_, err = os.Stat(torrentFile(s.archiveManager.torrentConfig.TorrentDir, community.IDString()))
   574  	s.Require().Error(err)
   575  }
   576  
   577  func (s *ManagerSuite) TestCreateHistoryArchiveTorrent_ShouldCreateArchive() {
   578  	community, chatID, err := s.buildCommunityWithChat()
   579  	s.Require().NoError(err)
   580  
   581  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   582  	topics := []types.TopicType{topic}
   583  
   584  	// Time range of 7 days
   585  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   586  	endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   587  	// Partition of 7 days, this should create a single archive
   588  	partition := 7 * 24 * time.Hour
   589  
   590  	message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1})
   591  	message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2})
   592  	// This message is outside of the startDate-endDate range and should not
   593  	// be part of the archive
   594  	message3 := buildMessage(endDate.Add(2*time.Hour), topic, []byte{3})
   595  
   596  	err = s.manager.StoreWakuMessage(&message1)
   597  	s.Require().NoError(err)
   598  	err = s.manager.StoreWakuMessage(&message2)
   599  	s.Require().NoError(err)
   600  	err = s.manager.StoreWakuMessage(&message3)
   601  	s.Require().NoError(err)
   602  
   603  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false)
   604  	s.Require().NoError(err)
   605  
   606  	_, err = os.Stat(s.archiveManager.archiveDataFile(community.IDString()))
   607  	s.Require().NoError(err)
   608  	_, err = os.Stat(s.archiveManager.archiveIndexFile(community.IDString()))
   609  	s.Require().NoError(err)
   610  	_, err = os.Stat(torrentFile(s.archiveManager.torrentConfig.TorrentDir, community.IDString()))
   611  	s.Require().NoError(err)
   612  
   613  	index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID())
   614  	s.Require().NoError(err)
   615  	s.Require().Len(index.Archives, 1)
   616  
   617  	totalData, err := os.ReadFile(s.archiveManager.archiveDataFile(community.IDString()))
   618  	s.Require().NoError(err)
   619  
   620  	for _, metadata := range index.Archives {
   621  		archive := &protobuf.WakuMessageArchive{}
   622  		data := totalData[metadata.Offset : metadata.Offset+metadata.Size-metadata.Padding]
   623  
   624  		err = proto.Unmarshal(data, archive)
   625  		s.Require().NoError(err)
   626  
   627  		s.Require().Len(archive.Messages, 2)
   628  	}
   629  }
   630  
   631  func (s *ManagerSuite) TestCreateHistoryArchiveTorrent_ShouldCreateMultipleArchives() {
   632  	community, chatID, err := s.buildCommunityWithChat()
   633  	s.Require().NoError(err)
   634  
   635  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   636  	topics := []types.TopicType{topic}
   637  
   638  	// Time range of 3 weeks
   639  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   640  	endDate := time.Date(2020, 1, 21, 00, 00, 00, 0, time.UTC)
   641  	// 7 days partition, this should create three archives
   642  	partition := 7 * 24 * time.Hour
   643  
   644  	message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1})
   645  	message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2})
   646  	// We expect 2 archives to be created for startDate - endDate of each
   647  	// 7 days of data. This message should end up in the second archive
   648  	message3 := buildMessage(startDate.Add(8*24*time.Hour), topic, []byte{3})
   649  	// This one should end up in the third archive
   650  	message4 := buildMessage(startDate.Add(14*24*time.Hour), topic, []byte{4})
   651  
   652  	err = s.manager.StoreWakuMessage(&message1)
   653  	s.Require().NoError(err)
   654  	err = s.manager.StoreWakuMessage(&message2)
   655  	s.Require().NoError(err)
   656  	err = s.manager.StoreWakuMessage(&message3)
   657  	s.Require().NoError(err)
   658  	err = s.manager.StoreWakuMessage(&message4)
   659  	s.Require().NoError(err)
   660  
   661  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false)
   662  	s.Require().NoError(err)
   663  
   664  	index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID())
   665  	s.Require().NoError(err)
   666  	s.Require().Len(index.Archives, 3)
   667  
   668  	totalData, err := os.ReadFile(s.archiveManager.archiveDataFile(community.IDString()))
   669  	s.Require().NoError(err)
   670  
   671  	// First archive has 2 messages
   672  	// Second archive has 1 message
   673  	// Third archive has 1 message
   674  	fromMap := map[uint64]int{
   675  		uint64(startDate.Unix()):                    2,
   676  		uint64(startDate.Add(partition).Unix()):     1,
   677  		uint64(startDate.Add(partition * 2).Unix()): 1,
   678  	}
   679  
   680  	for _, metadata := range index.Archives {
   681  		archive := &protobuf.WakuMessageArchive{}
   682  		data := totalData[metadata.Offset : metadata.Offset+metadata.Size-metadata.Padding]
   683  
   684  		err = proto.Unmarshal(data, archive)
   685  		s.Require().NoError(err)
   686  		s.Require().Len(archive.Messages, fromMap[metadata.Metadata.From])
   687  	}
   688  }
   689  
   690  func (s *ManagerSuite) TestCreateHistoryArchiveTorrent_ShouldAppendArchives() {
   691  	community, chatID, err := s.buildCommunityWithChat()
   692  	s.Require().NoError(err)
   693  
   694  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   695  	topics := []types.TopicType{topic}
   696  
   697  	// Time range of 1 week
   698  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   699  	endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   700  	// 7 days partition, this should create one archive
   701  	partition := 7 * 24 * time.Hour
   702  
   703  	message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1})
   704  	err = s.manager.StoreWakuMessage(&message1)
   705  	s.Require().NoError(err)
   706  
   707  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false)
   708  	s.Require().NoError(err)
   709  
   710  	index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID())
   711  	s.Require().NoError(err)
   712  	s.Require().Len(index.Archives, 1)
   713  
   714  	// Time range of next week
   715  	startDate = time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   716  	endDate = time.Date(2020, 1, 14, 00, 00, 00, 0, time.UTC)
   717  
   718  	message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2})
   719  	err = s.manager.StoreWakuMessage(&message2)
   720  	s.Require().NoError(err)
   721  
   722  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false)
   723  	s.Require().NoError(err)
   724  
   725  	index, err = s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID())
   726  	s.Require().NoError(err)
   727  	s.Require().Len(index.Archives, 2)
   728  }
   729  
   730  func (s *ManagerSuite) TestCreateHistoryArchiveTorrentFromMessages() {
   731  	community, chatID, err := s.buildCommunityWithChat()
   732  	s.Require().NoError(err)
   733  
   734  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   735  	topics := []types.TopicType{topic}
   736  
   737  	// Time range of 7 days
   738  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   739  	endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   740  	// Partition of 7 days, this should create a single archive
   741  	partition := 7 * 24 * time.Hour
   742  
   743  	message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1})
   744  	message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2})
   745  	// This message is outside of the startDate-endDate range and should not
   746  	// be part of the archive
   747  	message3 := buildMessage(endDate.Add(2*time.Hour), topic, []byte{3})
   748  
   749  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromMessages(community.ID(), []*types.Message{&message1, &message2, &message3}, topics, startDate, endDate, partition, false)
   750  	s.Require().NoError(err)
   751  
   752  	_, err = os.Stat(s.archiveManager.archiveDataFile(community.IDString()))
   753  	s.Require().NoError(err)
   754  	_, err = os.Stat(s.archiveManager.archiveIndexFile(community.IDString()))
   755  	s.Require().NoError(err)
   756  	_, err = os.Stat(torrentFile(s.archiveManager.torrentConfig.TorrentDir, community.IDString()))
   757  	s.Require().NoError(err)
   758  
   759  	index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID())
   760  	s.Require().NoError(err)
   761  	s.Require().Len(index.Archives, 1)
   762  
   763  	totalData, err := os.ReadFile(s.archiveManager.archiveDataFile(community.IDString()))
   764  	s.Require().NoError(err)
   765  
   766  	for _, metadata := range index.Archives {
   767  		archive := &protobuf.WakuMessageArchive{}
   768  		data := totalData[metadata.Offset : metadata.Offset+metadata.Size-metadata.Padding]
   769  
   770  		err = proto.Unmarshal(data, archive)
   771  		s.Require().NoError(err)
   772  
   773  		s.Require().Len(archive.Messages, 2)
   774  	}
   775  }
   776  
   777  func (s *ManagerSuite) TestCreateHistoryArchiveTorrentFromMessages_ShouldCreateMultipleArchives() {
   778  	community, chatID, err := s.buildCommunityWithChat()
   779  	s.Require().NoError(err)
   780  
   781  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   782  	topics := []types.TopicType{topic}
   783  
   784  	// Time range of 3 weeks
   785  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   786  	endDate := time.Date(2020, 1, 21, 00, 00, 00, 0, time.UTC)
   787  	// 7 days partition, this should create three archives
   788  	partition := 7 * 24 * time.Hour
   789  
   790  	message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1})
   791  	message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2})
   792  	// We expect 2 archives to be created for startDate - endDate of each
   793  	// 7 days of data. This message should end up in the second archive
   794  	message3 := buildMessage(startDate.Add(8*24*time.Hour), topic, []byte{3})
   795  	// This one should end up in the third archive
   796  	message4 := buildMessage(startDate.Add(14*24*time.Hour), topic, []byte{4})
   797  
   798  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromMessages(community.ID(), []*types.Message{&message1, &message2, &message3, &message4}, topics, startDate, endDate, partition, false)
   799  	s.Require().NoError(err)
   800  
   801  	index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID())
   802  	s.Require().NoError(err)
   803  	s.Require().Len(index.Archives, 3)
   804  
   805  	totalData, err := os.ReadFile(s.archiveManager.archiveDataFile(community.IDString()))
   806  	s.Require().NoError(err)
   807  
   808  	// First archive has 2 messages
   809  	// Second archive has 1 message
   810  	// Third archive has 1 message
   811  	fromMap := map[uint64]int{
   812  		uint64(startDate.Unix()):                    2,
   813  		uint64(startDate.Add(partition).Unix()):     1,
   814  		uint64(startDate.Add(partition * 2).Unix()): 1,
   815  	}
   816  
   817  	for _, metadata := range index.Archives {
   818  		archive := &protobuf.WakuMessageArchive{}
   819  		data := totalData[metadata.Offset : metadata.Offset+metadata.Size-metadata.Padding]
   820  
   821  		err = proto.Unmarshal(data, archive)
   822  		s.Require().NoError(err)
   823  		s.Require().Len(archive.Messages, fromMap[metadata.Metadata.From])
   824  	}
   825  }
   826  
   827  func (s *ManagerSuite) TestCreateHistoryArchiveTorrentFromMessages_ShouldAppendArchives() {
   828  	community, chatID, err := s.buildCommunityWithChat()
   829  	s.Require().NoError(err)
   830  
   831  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   832  	topics := []types.TopicType{topic}
   833  
   834  	// Time range of 1 week
   835  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   836  	endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   837  	// 7 days partition, this should create one archive
   838  	partition := 7 * 24 * time.Hour
   839  
   840  	message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1})
   841  
   842  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromMessages(community.ID(), []*types.Message{&message1}, topics, startDate, endDate, partition, false)
   843  	s.Require().NoError(err)
   844  
   845  	index, err := s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID())
   846  	s.Require().NoError(err)
   847  	s.Require().Len(index.Archives, 1)
   848  
   849  	// Time range of next week
   850  	startDate = time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   851  	endDate = time.Date(2020, 1, 14, 00, 00, 00, 0, time.UTC)
   852  
   853  	message2 := buildMessage(startDate.Add(2*time.Hour), topic, []byte{2})
   854  
   855  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromMessages(community.ID(), []*types.Message{&message2}, topics, startDate, endDate, partition, false)
   856  	s.Require().NoError(err)
   857  
   858  	index, err = s.archiveManager.LoadHistoryArchiveIndexFromFile(s.manager.identity, community.ID())
   859  	s.Require().NoError(err)
   860  	s.Require().Len(index.Archives, 2)
   861  }
   862  
   863  func (s *ManagerSuite) TestSeedHistoryArchiveTorrent() {
   864  	err := s.archiveManager.StartTorrentClient()
   865  	s.Require().NoError(err)
   866  	defer s.archiveManager.Stop() //nolint: errcheck
   867  
   868  	community, chatID, err := s.buildCommunityWithChat()
   869  	s.Require().NoError(err)
   870  
   871  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   872  	topics := []types.TopicType{topic}
   873  
   874  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   875  	endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   876  	partition := 7 * 24 * time.Hour
   877  
   878  	message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1})
   879  	err = s.manager.StoreWakuMessage(&message1)
   880  	s.Require().NoError(err)
   881  
   882  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false)
   883  	s.Require().NoError(err)
   884  
   885  	err = s.archiveManager.SeedHistoryArchiveTorrent(community.ID())
   886  	s.Require().NoError(err)
   887  	s.Require().Len(s.archiveManager.torrentTasks, 1)
   888  
   889  	metaInfoHash := s.archiveManager.torrentTasks[community.IDString()]
   890  	torrent, ok := s.archiveManager.torrentClient.Torrent(metaInfoHash)
   891  	defer torrent.Drop()
   892  
   893  	s.Require().Equal(ok, true)
   894  	s.Require().Equal(torrent.Seeding(), true)
   895  }
   896  
   897  func (s *ManagerSuite) TestUnseedHistoryArchiveTorrent() {
   898  	err := s.archiveManager.StartTorrentClient()
   899  	s.Require().NoError(err)
   900  	defer s.archiveManager.Stop() //nolint: errcheck
   901  
   902  	community, chatID, err := s.buildCommunityWithChat()
   903  	s.Require().NoError(err)
   904  
   905  	topic := types.BytesToTopic(transport.ToTopic(chatID))
   906  	topics := []types.TopicType{topic}
   907  
   908  	startDate := time.Date(2020, 1, 1, 00, 00, 00, 0, time.UTC)
   909  	endDate := time.Date(2020, 1, 7, 00, 00, 00, 0, time.UTC)
   910  	partition := 7 * 24 * time.Hour
   911  
   912  	message1 := buildMessage(startDate.Add(1*time.Hour), topic, []byte{1})
   913  	err = s.manager.StoreWakuMessage(&message1)
   914  	s.Require().NoError(err)
   915  
   916  	_, err = s.archiveManager.CreateHistoryArchiveTorrentFromDB(community.ID(), topics, startDate, endDate, partition, false)
   917  	s.Require().NoError(err)
   918  
   919  	err = s.archiveManager.SeedHistoryArchiveTorrent(community.ID())
   920  	s.Require().NoError(err)
   921  	s.Require().Len(s.archiveManager.torrentTasks, 1)
   922  
   923  	metaInfoHash := s.archiveManager.torrentTasks[community.IDString()]
   924  
   925  	s.archiveManager.UnseedHistoryArchiveTorrent(community.ID())
   926  	_, ok := s.archiveManager.torrentClient.Torrent(metaInfoHash)
   927  	s.Require().Equal(ok, false)
   928  }
   929  
   930  func (s *ManagerSuite) TestCheckChannelPermissions_NoPermissions() {
   931  
   932  	m, _, tm := s.setupManagerForTokenPermissions()
   933  
   934  	var chainID uint64 = 5
   935  	contractAddresses := make(map[uint64]string)
   936  	contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
   937  
   938  	accountChainIDsCombination := []*AccountChainIDsCombination{
   939  		&AccountChainIDsCombination{
   940  			Address:  gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
   941  			ChainIDs: []uint64{chainID},
   942  		},
   943  	}
   944  
   945  	var viewOnlyPermissions = make([]*CommunityTokenPermission, 0)
   946  	var viewAndPostPermissions = make([]*CommunityTokenPermission, 0)
   947  	viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
   948  	viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
   949  
   950  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
   951  	resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
   952  	s.Require().NoError(err)
   953  	s.Require().NotNil(resp)
   954  
   955  	// Both viewOnly and viewAndPost permissions are expected to be satisfied
   956  	// because we call `checkChannelPermissions()` with no permissions to check
   957  	s.Require().True(resp.ViewOnlyPermissions.Satisfied)
   958  	s.Require().True(resp.ViewAndPostPermissions.Satisfied)
   959  }
   960  
   961  func (s *ManagerSuite) TestCheckChannelPermissions_ViewOnlyPermissions() {
   962  
   963  	m, _, tm := s.setupManagerForTokenPermissions()
   964  
   965  	var chainID uint64 = 5
   966  	contractAddresses := make(map[uint64]string)
   967  	contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
   968  	var decimals uint64 = 18
   969  
   970  	accountChainIDsCombination := []*AccountChainIDsCombination{
   971  		&AccountChainIDsCombination{
   972  			Address:  gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
   973  			ChainIDs: []uint64{chainID},
   974  		},
   975  	}
   976  
   977  	var tokenCriteria = []*protobuf.TokenCriteria{
   978  		&protobuf.TokenCriteria{
   979  			ContractAddresses: contractAddresses,
   980  			Symbol:            "STT",
   981  			Type:              protobuf.CommunityTokenType_ERC20,
   982  			Name:              "Status Test Token",
   983  			AmountInWei:       "1000000000000000000",
   984  			Decimals:          decimals,
   985  		},
   986  	}
   987  
   988  	var viewOnlyPermissions = []*CommunityTokenPermission{
   989  		&CommunityTokenPermission{
   990  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
   991  				Id:            "some-id",
   992  				Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
   993  				TokenCriteria: tokenCriteria,
   994  				ChatIds:       []string{"test-channel-id", "test-channel-id-2"},
   995  			},
   996  		},
   997  	}
   998  
   999  	var viewAndPostPermissions = make([]*CommunityTokenPermission, 0)
  1000  
  1001  	viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
  1002  	viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
  1003  
  1004  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
  1005  	resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
  1006  	s.Require().NoError(err)
  1007  	s.Require().NotNil(resp)
  1008  
  1009  	s.Require().False(resp.ViewOnlyPermissions.Satisfied)
  1010  	// if viewOnly permissions are not satisfied then viewAndPost
  1011  	// permissions shouldn't be satisfied either
  1012  	s.Require().False(resp.ViewAndPostPermissions.Satisfied)
  1013  
  1014  	// Set response to exactly the right one
  1015  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
  1016  	resp, err = m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
  1017  	s.Require().NoError(err)
  1018  	s.Require().NotNil(resp)
  1019  
  1020  	s.Require().True(resp.ViewOnlyPermissions.Satisfied)
  1021  	s.Require().False(resp.ViewAndPostPermissions.Satisfied)
  1022  }
  1023  
  1024  func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissions() {
  1025  
  1026  	m, _, tm := s.setupManagerForTokenPermissions()
  1027  
  1028  	var chainID uint64 = 5
  1029  	contractAddresses := make(map[uint64]string)
  1030  	contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
  1031  	var decimals uint64 = 18
  1032  
  1033  	accountChainIDsCombination := []*AccountChainIDsCombination{
  1034  		&AccountChainIDsCombination{
  1035  			Address:  gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1036  			ChainIDs: []uint64{chainID},
  1037  		},
  1038  	}
  1039  
  1040  	var tokenCriteria = []*protobuf.TokenCriteria{
  1041  		&protobuf.TokenCriteria{
  1042  			ContractAddresses: contractAddresses,
  1043  			Symbol:            "STT",
  1044  			Type:              protobuf.CommunityTokenType_ERC20,
  1045  			Name:              "Status Test Token",
  1046  			AmountInWei:       "1000000000000000000",
  1047  			Decimals:          decimals,
  1048  		},
  1049  	}
  1050  
  1051  	var viewAndPostPermissions = []*CommunityTokenPermission{
  1052  		&CommunityTokenPermission{
  1053  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
  1054  				Id:            "some-id",
  1055  				Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1056  				TokenCriteria: tokenCriteria,
  1057  				ChatIds:       []string{"test-channel-id", "test-channel-id-2"},
  1058  			},
  1059  		},
  1060  	}
  1061  
  1062  	var viewOnlyPermissions = make([]*CommunityTokenPermission, 0)
  1063  
  1064  	viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
  1065  	viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
  1066  
  1067  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
  1068  	resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
  1069  	s.Require().NoError(err)
  1070  	s.Require().NotNil(resp)
  1071  
  1072  	s.Require().False(resp.ViewAndPostPermissions.Satisfied)
  1073  	// viewOnly permissions are flagged as not satisfied because we have no viewOnly
  1074  	// permissions on this channel and the viewAndPost permission is not satisfied either
  1075  	s.Require().False(resp.ViewOnlyPermissions.Satisfied)
  1076  
  1077  	// Set response to exactly the right one
  1078  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
  1079  	resp, err = m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
  1080  	s.Require().NoError(err)
  1081  	s.Require().NotNil(resp)
  1082  
  1083  	s.Require().True(resp.ViewAndPostPermissions.Satisfied)
  1084  	// if viewAndPost is satisfied then viewOnly should be automatically satisfied
  1085  	s.Require().True(resp.ViewOnlyPermissions.Satisfied)
  1086  }
  1087  
  1088  func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombination() {
  1089  
  1090  	m, _, tm := s.setupManagerForTokenPermissions()
  1091  
  1092  	var chainID uint64 = 5
  1093  	contractAddresses := make(map[uint64]string)
  1094  	contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
  1095  	var decimals uint64 = 18
  1096  
  1097  	accountChainIDsCombination := []*AccountChainIDsCombination{
  1098  		&AccountChainIDsCombination{
  1099  			Address:  gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1100  			ChainIDs: []uint64{chainID},
  1101  		},
  1102  	}
  1103  
  1104  	var viewOnlyTokenCriteria = []*protobuf.TokenCriteria{
  1105  		&protobuf.TokenCriteria{
  1106  			ContractAddresses: contractAddresses,
  1107  			Symbol:            "STT",
  1108  			Type:              protobuf.CommunityTokenType_ERC20,
  1109  			Name:              "Status Test Token",
  1110  			AmountInWei:       "1000000000000000000",
  1111  			Decimals:          decimals,
  1112  		},
  1113  	}
  1114  
  1115  	var viewOnlyPermissions = []*CommunityTokenPermission{
  1116  		&CommunityTokenPermission{
  1117  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
  1118  				Id:            "some-id",
  1119  				Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1120  				TokenCriteria: viewOnlyTokenCriteria,
  1121  				ChatIds:       []string{"test-channel-id", "test-channel-id-2"},
  1122  			},
  1123  		},
  1124  	}
  1125  
  1126  	testContractAddresses := make(map[uint64]string)
  1127  	testContractAddresses[chainID] = "0x123"
  1128  
  1129  	// Set up token criteria that won't be satisfied
  1130  	var viewAndPostTokenCriteria = []*protobuf.TokenCriteria{
  1131  		&protobuf.TokenCriteria{
  1132  			ContractAddresses: testContractAddresses,
  1133  			Symbol:            "TEST",
  1134  			Type:              protobuf.CommunityTokenType_ERC20,
  1135  			Name:              "TEST token",
  1136  			AmountInWei:       "1000000000000000000",
  1137  			Decimals:          decimals,
  1138  		},
  1139  	}
  1140  
  1141  	var viewAndPostPermissions = []*CommunityTokenPermission{
  1142  		&CommunityTokenPermission{
  1143  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
  1144  				Id:            "some-id",
  1145  				Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1146  				TokenCriteria: viewAndPostTokenCriteria,
  1147  				ChatIds:       []string{"test-channel-id", "test-channel-id-2"},
  1148  			},
  1149  		},
  1150  	}
  1151  
  1152  	// Set response for viewOnly permissions
  1153  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
  1154  	// Set resopnse for viewAndPost permissions
  1155  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(testContractAddresses[chainID]), 0)
  1156  
  1157  	viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
  1158  	viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
  1159  
  1160  	resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
  1161  	s.Require().NoError(err)
  1162  	s.Require().NotNil(resp)
  1163  
  1164  	// viewOnly permission should be satisfied, even though viewAndPost is not satisfied
  1165  	s.Require().True(resp.ViewOnlyPermissions.Satisfied)
  1166  	s.Require().False(resp.ViewAndPostPermissions.Satisfied)
  1167  }
  1168  
  1169  // Same as the one above, but reversed where the View permission is not satisfied, but the view and post is
  1170  func (s *ManagerSuite) TestCheckChannelPermissions_ViewAndPostPermissionsCombination2() {
  1171  
  1172  	m, _, tm := s.setupManagerForTokenPermissions()
  1173  
  1174  	var chainID uint64 = 5
  1175  	contractAddresses := make(map[uint64]string)
  1176  	contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
  1177  	var decimals uint64 = 18
  1178  
  1179  	accountChainIDsCombination := []*AccountChainIDsCombination{
  1180  		&AccountChainIDsCombination{
  1181  			Address:  gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1182  			ChainIDs: []uint64{chainID},
  1183  		},
  1184  	}
  1185  
  1186  	var viewOnlyTokenCriteria = []*protobuf.TokenCriteria{
  1187  		&protobuf.TokenCriteria{
  1188  			ContractAddresses: contractAddresses,
  1189  			Symbol:            "STT",
  1190  			Type:              protobuf.CommunityTokenType_ERC20,
  1191  			Name:              "Status Test Token",
  1192  			AmountInWei:       "1000000000000000000",
  1193  			Decimals:          decimals,
  1194  		},
  1195  	}
  1196  
  1197  	var viewOnlyPermissions = []*CommunityTokenPermission{
  1198  		&CommunityTokenPermission{
  1199  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
  1200  				Id:            "some-id",
  1201  				Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1202  				TokenCriteria: viewOnlyTokenCriteria,
  1203  				ChatIds:       []string{"test-channel-id", "test-channel-id-2"},
  1204  			},
  1205  		},
  1206  	}
  1207  
  1208  	testContractAddresses := make(map[uint64]string)
  1209  	testContractAddresses[chainID] = "0x123"
  1210  
  1211  	// Set up token criteria that won't be satisfied
  1212  	var viewAndPostTokenCriteria = []*protobuf.TokenCriteria{
  1213  		&protobuf.TokenCriteria{
  1214  			ContractAddresses: testContractAddresses,
  1215  			Symbol:            "TEST",
  1216  			Type:              protobuf.CommunityTokenType_ERC20,
  1217  			Name:              "TEST token",
  1218  			AmountInWei:       "1000000000000000000",
  1219  			Decimals:          decimals,
  1220  		},
  1221  	}
  1222  
  1223  	var viewAndPostPermissions = []*CommunityTokenPermission{
  1224  		&CommunityTokenPermission{
  1225  			CommunityTokenPermission: &protobuf.CommunityTokenPermission{
  1226  				Id:            "some-id",
  1227  				Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1228  				TokenCriteria: viewAndPostTokenCriteria,
  1229  				ChatIds:       []string{"test-channel-id", "test-channel-id-2"},
  1230  			},
  1231  		},
  1232  	}
  1233  
  1234  	// Set response for viewOnly permissions
  1235  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
  1236  	// Set resopnse for viewAndPost permissions
  1237  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(testContractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
  1238  
  1239  	viewOnlyPreParsedPermissions := preParsedCommunityPermissionsData(viewOnlyPermissions)
  1240  	viewAndPostPreParsedPermissions := preParsedCommunityPermissionsData(viewAndPostPermissions)
  1241  
  1242  	resp, err := m.checkChannelPermissions(viewOnlyPreParsedPermissions, viewAndPostPreParsedPermissions, accountChainIDsCombination, false)
  1243  	s.Require().NoError(err)
  1244  	s.Require().NotNil(resp)
  1245  
  1246  	// Both permissions should be satisfied, even though view is not satisfied
  1247  	s.Require().True(resp.ViewOnlyPermissions.Satisfied)
  1248  	s.Require().True(resp.ViewAndPostPermissions.Satisfied)
  1249  }
  1250  
  1251  func (s *ManagerSuite) TestCheckAllChannelsPermissions_EmptyPermissions() {
  1252  
  1253  	m, _, _ := s.setupManagerForTokenPermissions()
  1254  
  1255  	createRequest := &requests.CreateCommunity{
  1256  		Name:        "channel permission community",
  1257  		Description: "some description",
  1258  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
  1259  	}
  1260  	community, err := m.CreateCommunity(createRequest, true)
  1261  	s.Require().NoError(err)
  1262  
  1263  	// create community chats
  1264  	chat := &protobuf.CommunityChat{
  1265  		Identity: &protobuf.ChatIdentity{
  1266  			DisplayName: "chat1",
  1267  			Description: "description",
  1268  		},
  1269  		Permissions: &protobuf.CommunityPermissions{
  1270  			Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
  1271  		},
  1272  		Members: make(map[string]*protobuf.CommunityMember),
  1273  	}
  1274  
  1275  	changes, err := m.CreateChat(community.ID(), chat, true, "")
  1276  	s.Require().NoError(err)
  1277  
  1278  	var chatID string
  1279  	for cid := range changes.ChatsAdded {
  1280  		chatID = community.IDString() + cid
  1281  	}
  1282  
  1283  	response, err := m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{
  1284  		gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1285  	})
  1286  	s.Require().NoError(err)
  1287  	s.Require().NotNil(response)
  1288  
  1289  	s.Require().Len(response.Channels, 1)
  1290  	// we expect both, viewOnly and viewAndPost permissions to be satisfied
  1291  	// as there aren't any permissions on this channel
  1292  	s.Require().True(response.Channels[chatID].ViewOnlyPermissions.Satisfied)
  1293  	s.Require().True(response.Channels[chatID].ViewAndPostPermissions.Satisfied)
  1294  	s.Require().Len(response.Channels[chatID].ViewOnlyPermissions.Permissions, 0)
  1295  	s.Require().Len(response.Channels[chatID].ViewAndPostPermissions.Permissions, 0)
  1296  }
  1297  
  1298  func (s *ManagerSuite) TestCheckAllChannelsPermissions() {
  1299  
  1300  	m, _, tm := s.setupManagerForTokenPermissions()
  1301  
  1302  	var chatID1 string
  1303  	var chatID2 string
  1304  
  1305  	// create community
  1306  	createRequest := &requests.CreateCommunity{
  1307  		Name:        "channel permission community",
  1308  		Description: "some description",
  1309  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
  1310  	}
  1311  	community, err := m.CreateCommunity(createRequest, true)
  1312  	s.Require().NoError(err)
  1313  
  1314  	// create first community chat
  1315  	chat := &protobuf.CommunityChat{
  1316  		Identity: &protobuf.ChatIdentity{
  1317  			DisplayName: "chat1",
  1318  			Description: "description",
  1319  		},
  1320  		Permissions: &protobuf.CommunityPermissions{
  1321  			Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
  1322  		},
  1323  		Members: make(map[string]*protobuf.CommunityMember),
  1324  	}
  1325  
  1326  	changes, err := m.CreateChat(community.ID(), chat, true, "")
  1327  	s.Require().NoError(err)
  1328  
  1329  	for chatID := range changes.ChatsAdded {
  1330  		chatID1 = community.IDString() + chatID
  1331  	}
  1332  
  1333  	// create second community chat
  1334  	chat = &protobuf.CommunityChat{
  1335  		Identity: &protobuf.ChatIdentity{
  1336  			DisplayName: "chat2",
  1337  			Description: "description",
  1338  		},
  1339  		Permissions: &protobuf.CommunityPermissions{
  1340  			Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
  1341  		},
  1342  		Members: make(map[string]*protobuf.CommunityMember),
  1343  	}
  1344  
  1345  	changes, err = m.CreateChat(community.ID(), chat, true, "")
  1346  	s.Require().NoError(err)
  1347  
  1348  	for chatID := range changes.ChatsAdded {
  1349  		chatID2 = community.IDString() + chatID
  1350  	}
  1351  
  1352  	var chainID uint64 = 5
  1353  	contractAddresses := make(map[uint64]string)
  1354  	contractAddresses[chainID] = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
  1355  	var decimals uint64 = 18
  1356  
  1357  	accountChainIDsCombination := []*AccountChainIDsCombination{
  1358  		&AccountChainIDsCombination{
  1359  			Address:  gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1360  			ChainIDs: []uint64{chainID},
  1361  		},
  1362  	}
  1363  
  1364  	var tokenCriteria = []*protobuf.TokenCriteria{
  1365  		&protobuf.TokenCriteria{
  1366  			ContractAddresses: contractAddresses,
  1367  			Symbol:            "STT",
  1368  			Type:              protobuf.CommunityTokenType_ERC20,
  1369  			Name:              "Status Test Token",
  1370  			AmountInWei:       "1000000000000000000",
  1371  			Decimals:          decimals,
  1372  		},
  1373  	}
  1374  
  1375  	// create view only permission
  1376  	viewOnlyPermission := &requests.CreateCommunityTokenPermission{
  1377  		CommunityID:   community.ID(),
  1378  		Type:          protobuf.CommunityTokenPermission_CAN_VIEW_CHANNEL,
  1379  		TokenCriteria: tokenCriteria,
  1380  		ChatIds:       []string{chatID1, chatID2},
  1381  	}
  1382  
  1383  	_, changes, err = m.CreateCommunityTokenPermission(viewOnlyPermission)
  1384  	s.Require().NoError(err)
  1385  
  1386  	var viewOnlyPermissionID string
  1387  	for permissionID := range changes.TokenPermissionsAdded {
  1388  		viewOnlyPermissionID = permissionID
  1389  	}
  1390  
  1391  	response, err := m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{
  1392  		gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1393  	})
  1394  	s.Require().NoError(err)
  1395  	s.Require().NotNil(response)
  1396  
  1397  	// we've added to chats to the community, so there should be 2 items
  1398  	s.Require().Len(response.Channels, 2)
  1399  
  1400  	// viewOnly permissions should not be satisfied because the account doesn't
  1401  	// have the necessary funds
  1402  
  1403  	// channel1
  1404  	s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Satisfied)
  1405  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 1)
  1406  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1)
  1407  	s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0])
  1408  
  1409  	// channel2
  1410  	s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Satisfied)
  1411  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 1)
  1412  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1)
  1413  	s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0])
  1414  
  1415  	// viewAndPost permissions are flagged as not satisfied either because
  1416  	// viewOnly permission is not satisfied and there are no viewAndPost permissions
  1417  
  1418  	// channel1
  1419  	s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Satisfied)
  1420  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 0)
  1421  
  1422  	// channel2
  1423  	s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Satisfied)
  1424  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 0)
  1425  
  1426  	// now change balance such that viewOnly permission should be satisfied
  1427  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
  1428  
  1429  	response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{
  1430  		gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1431  	})
  1432  	s.Require().NoError(err)
  1433  	s.Require().NotNil(response)
  1434  	s.Require().Len(response.Channels, 2)
  1435  
  1436  	// viewOnly permissions should be satisfied for both channels while
  1437  	// viewAndPost permissions should not be satisfied (as there aren't any)
  1438  
  1439  	// channel1
  1440  	s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Satisfied)
  1441  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 1)
  1442  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1)
  1443  	s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0])
  1444  
  1445  	s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Satisfied)
  1446  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 0)
  1447  
  1448  	// channel2
  1449  	s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Satisfied)
  1450  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 1)
  1451  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1)
  1452  	s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0])
  1453  
  1454  	s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Satisfied)
  1455  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 0)
  1456  
  1457  	// next, create viewAndPost permission
  1458  	// create view only permission
  1459  	viewAndPostPermission := &requests.CreateCommunityTokenPermission{
  1460  		CommunityID:   community.ID(),
  1461  		Type:          protobuf.CommunityTokenPermission_CAN_VIEW_AND_POST_CHANNEL,
  1462  		TokenCriteria: tokenCriteria,
  1463  		ChatIds:       []string{chatID1, chatID2},
  1464  	}
  1465  
  1466  	_, changes, err = m.CreateCommunityTokenPermission(viewAndPostPermission)
  1467  	s.Require().NoError(err)
  1468  
  1469  	var viewAndPostPermissionID string
  1470  	for permissionID := range changes.TokenPermissionsAdded {
  1471  		viewAndPostPermissionID = permissionID
  1472  	}
  1473  
  1474  	// now change balance such that viewAndPost permission is not satisfied
  1475  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
  1476  
  1477  	response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{
  1478  		gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1479  	})
  1480  	s.Require().NoError(err)
  1481  	s.Require().NotNil(response)
  1482  	s.Require().Len(response.Channels, 2)
  1483  
  1484  	// Both, viewOnly and viewAndPost permissions exist on channel1 and channel2
  1485  	// but shouldn't be satisfied
  1486  
  1487  	// channel1
  1488  	s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Satisfied)
  1489  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 1)
  1490  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1)
  1491  	s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0])
  1492  
  1493  	s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Satisfied)
  1494  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 1)
  1495  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1)
  1496  	s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0])
  1497  
  1498  	// channel2
  1499  	s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Satisfied)
  1500  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 1)
  1501  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1)
  1502  	s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0])
  1503  
  1504  	s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Satisfied)
  1505  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 1)
  1506  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1)
  1507  	s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0])
  1508  
  1509  	// now change balance such that both, viewOnly and viewAndPost permission, are satisfied
  1510  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), int64(1*math.Pow(10, float64(decimals))))
  1511  
  1512  	response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{
  1513  		gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1514  	})
  1515  	s.Require().NoError(err)
  1516  	s.Require().NotNil(response)
  1517  	s.Require().Len(response.Channels, 2)
  1518  
  1519  	// Both, viewOnly and viewAndPost permissions exist on channel1 and channel2
  1520  	// and are satisfied
  1521  
  1522  	// channel1
  1523  	s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Satisfied)
  1524  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 1)
  1525  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1)
  1526  	s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0])
  1527  
  1528  	s.Require().True(response.Channels[chatID1].ViewAndPostPermissions.Satisfied)
  1529  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 1)
  1530  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1)
  1531  	s.Require().True(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0])
  1532  
  1533  	// channel2
  1534  	s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Satisfied)
  1535  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 1)
  1536  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria, 1)
  1537  	s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Permissions[viewOnlyPermissionID].Criteria[0])
  1538  
  1539  	s.Require().True(response.Channels[chatID2].ViewAndPostPermissions.Satisfied)
  1540  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 1)
  1541  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1)
  1542  	s.Require().True(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0])
  1543  
  1544  	// next, delete viewOnly permission so we can check the viewAndPost permission-only case
  1545  	deleteViewOnlyPermission := &requests.DeleteCommunityTokenPermission{
  1546  		CommunityID:  community.ID(),
  1547  		PermissionID: viewOnlyPermissionID,
  1548  	}
  1549  	_, _, err = m.DeleteCommunityTokenPermission(deleteViewOnlyPermission)
  1550  	s.Require().NoError(err)
  1551  
  1552  	response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{
  1553  		gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1554  	})
  1555  	s.Require().NoError(err)
  1556  	s.Require().NotNil(response)
  1557  	s.Require().Len(response.Channels, 2)
  1558  
  1559  	// Both, channel1 and channel2 now have viewAndPost only permissions that should
  1560  	// be satisfied, there's no viewOnly permission anymore the response should mark it
  1561  	// as satisfied as well
  1562  
  1563  	// channel1
  1564  	s.Require().True(response.Channels[chatID1].ViewAndPostPermissions.Satisfied)
  1565  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 1)
  1566  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1)
  1567  	s.Require().True(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0])
  1568  
  1569  	s.Require().True(response.Channels[chatID1].ViewOnlyPermissions.Satisfied)
  1570  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 0)
  1571  
  1572  	// channel2
  1573  	s.Require().True(response.Channels[chatID2].ViewAndPostPermissions.Satisfied)
  1574  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 1)
  1575  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1)
  1576  	s.Require().True(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0])
  1577  
  1578  	s.Require().True(response.Channels[chatID2].ViewOnlyPermissions.Satisfied)
  1579  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 0)
  1580  
  1581  	// now change balance such that viewAndPost permission is no longer satisfied
  1582  	tm.setResponse(chainID, accountChainIDsCombination[0].Address, gethcommon.HexToAddress(contractAddresses[chainID]), 0)
  1583  
  1584  	response, err = m.CheckAllChannelsPermissions(community.ID(), []gethcommon.Address{
  1585  		gethcommon.HexToAddress("0xD6b912e09E797D291E8D0eA3D3D17F8000e01c32"),
  1586  	})
  1587  	s.Require().NoError(err)
  1588  	s.Require().NotNil(response)
  1589  	s.Require().Len(response.Channels, 2)
  1590  
  1591  	// because viewAndPost permission is not satisfied and there are no viewOnly permissions
  1592  	// on the channels, the response should mark the viewOnly permissions as not satisfied as well
  1593  
  1594  	// channel1
  1595  	s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Satisfied)
  1596  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions, 1)
  1597  	s.Require().Len(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1)
  1598  	s.Require().False(response.Channels[chatID1].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0])
  1599  
  1600  	s.Require().False(response.Channels[chatID1].ViewOnlyPermissions.Satisfied)
  1601  	s.Require().Len(response.Channels[chatID1].ViewOnlyPermissions.Permissions, 0)
  1602  
  1603  	// channel2
  1604  	s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Satisfied)
  1605  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions, 1)
  1606  	s.Require().Len(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria, 1)
  1607  	s.Require().False(response.Channels[chatID2].ViewAndPostPermissions.Permissions[viewAndPostPermissionID].Criteria[0])
  1608  
  1609  	s.Require().False(response.Channels[chatID2].ViewOnlyPermissions.Satisfied)
  1610  	s.Require().Len(response.Channels[chatID2].ViewOnlyPermissions.Permissions, 0)
  1611  }
  1612  
  1613  func buildTorrentConfig() *params.TorrentConfig {
  1614  	return &params.TorrentConfig{
  1615  		Enabled:    true,
  1616  		DataDir:    os.TempDir() + "/archivedata",
  1617  		TorrentDir: os.TempDir() + "/torrents",
  1618  		Port:       0,
  1619  	}
  1620  }
  1621  
  1622  func buildMessage(timestamp time.Time, topic types.TopicType, hash []byte) types.Message {
  1623  	message := types.Message{
  1624  		Sig:       []byte{1},
  1625  		Timestamp: uint32(timestamp.Unix()),
  1626  		Topic:     topic,
  1627  		Payload:   []byte{1},
  1628  		Padding:   []byte{1},
  1629  		Hash:      hash,
  1630  	}
  1631  	return message
  1632  }
  1633  
  1634  func (s *ManagerSuite) buildCommunityWithChat() (*Community, string, error) {
  1635  	createRequest := &requests.CreateCommunity{
  1636  		Name:        "status",
  1637  		Description: "status community description",
  1638  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
  1639  	}
  1640  	community, err := s.manager.CreateCommunity(createRequest, true)
  1641  	if err != nil {
  1642  		return nil, "", err
  1643  	}
  1644  	chat := &protobuf.CommunityChat{
  1645  		Identity: &protobuf.ChatIdentity{
  1646  			DisplayName: "added-chat",
  1647  			Description: "description",
  1648  		},
  1649  		Permissions: &protobuf.CommunityPermissions{
  1650  			Access: protobuf.CommunityPermissions_AUTO_ACCEPT,
  1651  		},
  1652  		Members: make(map[string]*protobuf.CommunityMember),
  1653  	}
  1654  	changes, err := s.manager.CreateChat(community.ID(), chat, true, "")
  1655  	if err != nil {
  1656  		return nil, "", err
  1657  	}
  1658  
  1659  	chatID := ""
  1660  	for cID := range changes.ChatsAdded {
  1661  		chatID = cID
  1662  		break
  1663  	}
  1664  	return community, chatID, nil
  1665  }
  1666  
  1667  type testOwnerVerifier struct {
  1668  	called    int
  1669  	ownersMap map[string]string
  1670  }
  1671  
  1672  func (t *testOwnerVerifier) SafeGetSignerPubKey(ctx context.Context, chainID uint64, communityID string) (string, error) {
  1673  	t.called++
  1674  	return t.ownersMap[communityID], nil
  1675  }
  1676  
  1677  func (s *ManagerSuite) TestCommunityQueue() {
  1678  
  1679  	owner, err := crypto.GenerateKey()
  1680  	s.Require().NoError(err)
  1681  
  1682  	verifier := &testOwnerVerifier{}
  1683  	m, _ := s.buildManagers(verifier)
  1684  
  1685  	createRequest := &requests.CreateCommunity{
  1686  		Name:        "status",
  1687  		Description: "status community description",
  1688  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
  1689  	}
  1690  	community, err := s.manager.CreateCommunity(createRequest, true)
  1691  	s.Require().NoError(err)
  1692  
  1693  	// set verifier public key
  1694  	verifier.ownersMap = make(map[string]string)
  1695  	verifier.ownersMap[community.IDString()] = common.PubkeyToHex(&owner.PublicKey)
  1696  
  1697  	description := community.config.CommunityDescription
  1698  
  1699  	// safety check
  1700  	s.Require().Equal(uint64(0), CommunityDescriptionTokenOwnerChainID(description))
  1701  
  1702  	// set up permissions
  1703  	description.TokenPermissions = make(map[string]*protobuf.CommunityTokenPermission)
  1704  	description.TokenPermissions["some-id"] = &protobuf.CommunityTokenPermission{
  1705  		Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER,
  1706  		Id:   "some-token-id",
  1707  		TokenCriteria: []*protobuf.TokenCriteria{
  1708  			&protobuf.TokenCriteria{
  1709  				ContractAddresses: map[uint64]string{
  1710  					2: "some-address",
  1711  				},
  1712  			},
  1713  		}}
  1714  
  1715  	// Should have now a token owner
  1716  	s.Require().Equal(uint64(2), CommunityDescriptionTokenOwnerChainID(description))
  1717  
  1718  	payload, err := community.MarshaledDescription()
  1719  	s.Require().NoError(err)
  1720  
  1721  	payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, owner)
  1722  	s.Require().NoError(err)
  1723  
  1724  	// Create a signer, that is not the owner
  1725  	notTheOwner, err := crypto.GenerateKey()
  1726  	s.Require().NoError(err)
  1727  
  1728  	subscription := m.Subscribe()
  1729  
  1730  	response, err := m.HandleCommunityDescriptionMessage(&notTheOwner.PublicKey, description, payload, nil, nil)
  1731  	s.Require().NoError(err)
  1732  
  1733  	// No response, as it should be queued
  1734  	s.Require().Nil(response)
  1735  
  1736  	published := false
  1737  
  1738  	for !published {
  1739  		select {
  1740  		case event := <-subscription:
  1741  			if event.TokenCommunityValidated == nil {
  1742  				continue
  1743  			}
  1744  			published = true
  1745  		case <-time.After(2 * time.Second):
  1746  			s.FailNow("no subscription")
  1747  		}
  1748  	}
  1749  
  1750  	// Check it's not called multiple times
  1751  	s.Require().Equal(1, verifier.called)
  1752  	// Cleans up the communities to validate
  1753  	communitiesToValidate, err := m.persistence.getCommunitiesToValidate()
  1754  	s.Require().NoError(err)
  1755  	s.Require().Empty(communitiesToValidate)
  1756  }
  1757  
  1758  // 1) We create a community
  1759  // 2) We have 2 owners, but only new owner is returned by the contract
  1760  // 3) We receive the old owner community first
  1761  // 4) We receive the new owner community second
  1762  // 5) We start the queue
  1763  // 6) We should only process 4, and ignore anything else if that is successful, as that's the most recent
  1764  
  1765  func (s *ManagerSuite) TestCommunityQueueMultipleDifferentSigners() {
  1766  
  1767  	newOwner, err := crypto.GenerateKey()
  1768  	s.Require().NoError(err)
  1769  
  1770  	oldOwner, err := crypto.GenerateKey()
  1771  	s.Require().NoError(err)
  1772  
  1773  	verifier := &testOwnerVerifier{}
  1774  	m, _ := s.buildManagers(verifier)
  1775  
  1776  	createRequest := &requests.CreateCommunity{
  1777  		Name:        "status",
  1778  		Description: "status community description",
  1779  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
  1780  	}
  1781  	community, err := s.manager.CreateCommunity(createRequest, true)
  1782  	s.Require().NoError(err)
  1783  
  1784  	// set verifier public key
  1785  	verifier.ownersMap = make(map[string]string)
  1786  	verifier.ownersMap[community.IDString()] = common.PubkeyToHex(&newOwner.PublicKey)
  1787  
  1788  	description := community.config.CommunityDescription
  1789  
  1790  	// safety check
  1791  	s.Require().Equal(uint64(0), CommunityDescriptionTokenOwnerChainID(description))
  1792  
  1793  	// set up permissions
  1794  	description.TokenPermissions = make(map[string]*protobuf.CommunityTokenPermission)
  1795  	description.TokenPermissions["some-id"] = &protobuf.CommunityTokenPermission{
  1796  		Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER,
  1797  		Id:   "some-token-id",
  1798  		TokenCriteria: []*protobuf.TokenCriteria{
  1799  			&protobuf.TokenCriteria{
  1800  				ContractAddresses: map[uint64]string{
  1801  					2: "some-address",
  1802  				},
  1803  			},
  1804  		}}
  1805  
  1806  	// Should have now a token owner
  1807  	s.Require().Equal(uint64(2), CommunityDescriptionTokenOwnerChainID(description))
  1808  
  1809  	// We nil owner verifier so that messages won't be processed
  1810  	m.ownerVerifier = nil
  1811  
  1812  	// Send message from old owner first
  1813  
  1814  	payload, err := community.MarshaledDescription()
  1815  	s.Require().NoError(err)
  1816  
  1817  	payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, oldOwner)
  1818  	s.Require().NoError(err)
  1819  
  1820  	subscription := m.Subscribe()
  1821  
  1822  	response, err := m.HandleCommunityDescriptionMessage(&oldOwner.PublicKey, description, payload, nil, nil)
  1823  	s.Require().NoError(err)
  1824  
  1825  	// No response, as it should be queued
  1826  	s.Require().Nil(response)
  1827  
  1828  	// Send message from new owner now
  1829  
  1830  	community.config.CommunityDescription.Clock++
  1831  
  1832  	clock2 := community.config.CommunityDescription.Clock
  1833  
  1834  	payload, err = community.MarshaledDescription()
  1835  	s.Require().NoError(err)
  1836  
  1837  	payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, newOwner)
  1838  	s.Require().NoError(err)
  1839  
  1840  	response, err = m.HandleCommunityDescriptionMessage(&newOwner.PublicKey, description, payload, nil, nil)
  1841  	s.Require().NoError(err)
  1842  
  1843  	// No response, as it should be queued
  1844  	s.Require().Nil(response)
  1845  
  1846  	count, err := m.persistence.getCommunitiesToValidateCount()
  1847  	s.Require().NoError(err)
  1848  	s.Require().Equal(2, count)
  1849  
  1850  	communitiesToValidate, err := m.persistence.getCommunitiesToValidate()
  1851  	s.Require().NoError(err)
  1852  	s.Require().NotNil(communitiesToValidate)
  1853  	s.Require().NotNil(communitiesToValidate[community.IDString()])
  1854  	s.Require().Len(communitiesToValidate[community.IDString()], 2)
  1855  
  1856  	// We set owner verifier so that we start processing the queue
  1857  	m.ownerVerifier = verifier
  1858  
  1859  	published := false
  1860  
  1861  	for !published {
  1862  		select {
  1863  		case event := <-subscription:
  1864  			if event.TokenCommunityValidated == nil {
  1865  				continue
  1866  			}
  1867  			published = true
  1868  		case <-time.After(2 * time.Second):
  1869  			s.FailNow("no subscription")
  1870  		}
  1871  	}
  1872  
  1873  	// Check it's not called multiple times, since we should be checking newest first
  1874  	s.Require().Equal(1, verifier.called)
  1875  	// Cleans up the communities to validate
  1876  	communitiesToValidate, err = m.persistence.getCommunitiesToValidate()
  1877  	s.Require().NoError(err)
  1878  	s.Require().Empty(communitiesToValidate)
  1879  
  1880  	// Check clock of community is of the last community description
  1881  	fetchedCommunity, err := m.GetByID(community.ID())
  1882  	s.Require().NoError(err)
  1883  	s.Require().Equal(clock2, fetchedCommunity.config.CommunityDescription.Clock)
  1884  
  1885  }
  1886  
  1887  // 1) We create a community
  1888  // 2) We have 2 owners, but only old owner is returned by the contract
  1889  // 3) We receive the old owner community first
  1890  // 4) We receive the new owner community second (that could be a malicious user)
  1891  // 5) We start the queue
  1892  // 6) We should process both, but ignore the last community description
  1893  
  1894  func (s *ManagerSuite) TestCommunityQueueMultipleDifferentSignersIgnoreIfNotReturned() {
  1895  
  1896  	newOwner, err := crypto.GenerateKey()
  1897  	s.Require().NoError(err)
  1898  
  1899  	oldOwner, err := crypto.GenerateKey()
  1900  	s.Require().NoError(err)
  1901  
  1902  	verifier := &testOwnerVerifier{}
  1903  	m, _ := s.buildManagers(verifier)
  1904  
  1905  	createRequest := &requests.CreateCommunity{
  1906  		Name:        "status",
  1907  		Description: "status community description",
  1908  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
  1909  	}
  1910  	community, err := s.manager.CreateCommunity(createRequest, true)
  1911  	s.Require().NoError(err)
  1912  
  1913  	// set verifier public key
  1914  	verifier.ownersMap = make(map[string]string)
  1915  	verifier.ownersMap[community.IDString()] = common.PubkeyToHex(&oldOwner.PublicKey)
  1916  
  1917  	description := community.config.CommunityDescription
  1918  
  1919  	// safety check
  1920  	s.Require().Equal(uint64(0), CommunityDescriptionTokenOwnerChainID(description))
  1921  
  1922  	// set up permissions
  1923  	description.TokenPermissions = make(map[string]*protobuf.CommunityTokenPermission)
  1924  	description.TokenPermissions["some-id"] = &protobuf.CommunityTokenPermission{
  1925  		Type: protobuf.CommunityTokenPermission_BECOME_TOKEN_OWNER,
  1926  		Id:   "some-token-id",
  1927  		TokenCriteria: []*protobuf.TokenCriteria{
  1928  			&protobuf.TokenCriteria{
  1929  				ContractAddresses: map[uint64]string{
  1930  					2: "some-address",
  1931  				},
  1932  			},
  1933  		}}
  1934  
  1935  	// Should have now a token owner
  1936  	s.Require().Equal(uint64(2), CommunityDescriptionTokenOwnerChainID(description))
  1937  
  1938  	// We nil owner verifier so that messages won't be processed
  1939  	m.ownerVerifier = nil
  1940  
  1941  	clock1 := community.config.CommunityDescription.Clock
  1942  	// Send message from old owner first
  1943  
  1944  	payload, err := community.MarshaledDescription()
  1945  	s.Require().NoError(err)
  1946  
  1947  	payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, oldOwner)
  1948  	s.Require().NoError(err)
  1949  
  1950  	subscription := m.Subscribe()
  1951  
  1952  	response, err := m.HandleCommunityDescriptionMessage(&oldOwner.PublicKey, description, payload, nil, nil)
  1953  	s.Require().NoError(err)
  1954  
  1955  	// No response, as it should be queued
  1956  	s.Require().Nil(response)
  1957  
  1958  	// Send message from new owner now
  1959  
  1960  	community.config.CommunityDescription.Clock++
  1961  
  1962  	payload, err = community.MarshaledDescription()
  1963  	s.Require().NoError(err)
  1964  
  1965  	payload, err = v1.WrapMessageV1(payload, protobuf.ApplicationMetadataMessage_COMMUNITY_DESCRIPTION, newOwner)
  1966  	s.Require().NoError(err)
  1967  
  1968  	response, err = m.HandleCommunityDescriptionMessage(&newOwner.PublicKey, description, payload, nil, nil)
  1969  	s.Require().NoError(err)
  1970  
  1971  	// No response, as it should be queued
  1972  	s.Require().Nil(response)
  1973  
  1974  	count, err := m.persistence.getCommunitiesToValidateCount()
  1975  	s.Require().NoError(err)
  1976  	s.Require().Equal(2, count)
  1977  
  1978  	communitiesToValidate, err := m.persistence.getCommunitiesToValidate()
  1979  	s.Require().NoError(err)
  1980  	s.Require().NotNil(communitiesToValidate)
  1981  	s.Require().NotNil(communitiesToValidate[community.IDString()])
  1982  	s.Require().Len(communitiesToValidate[community.IDString()], 2)
  1983  
  1984  	// We set owner verifier so that we start processing the queue
  1985  	m.ownerVerifier = verifier
  1986  
  1987  	published := false
  1988  
  1989  	for !published {
  1990  		select {
  1991  		case event := <-subscription:
  1992  			if event.TokenCommunityValidated == nil {
  1993  				continue
  1994  			}
  1995  			published = true
  1996  		case <-time.After(2 * time.Second):
  1997  			s.FailNow("no subscription")
  1998  		}
  1999  	}
  2000  
  2001  	// Check it's not called multiple times, since we should be checking newest first
  2002  	s.Require().Equal(2, verifier.called)
  2003  	// Cleans up the communities to validate
  2004  	communitiesToValidate, err = m.persistence.getCommunitiesToValidate()
  2005  	s.Require().NoError(err)
  2006  	s.Require().Empty(communitiesToValidate)
  2007  
  2008  	// Check clock of community is of the first community description
  2009  	fetchedCommunity, err := m.GetByID(community.ID())
  2010  	s.Require().NoError(err)
  2011  	s.Require().Equal(clock1, fetchedCommunity.config.CommunityDescription.Clock)
  2012  }
  2013  
  2014  func (s *ManagerSuite) TestFillMissingCommunityTokens() {
  2015  	// Create community
  2016  	request := &requests.CreateCommunity{
  2017  		Name:        "status",
  2018  		Description: "token membership description",
  2019  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
  2020  	}
  2021  
  2022  	community, err := s.manager.CreateCommunity(request, true)
  2023  	s.Require().NoError(err)
  2024  	s.Require().NotNil(community)
  2025  	s.Require().Len(community.CommunityTokensMetadata(), 0)
  2026  
  2027  	// Create community token but without adding to the description
  2028  	token := community_token.CommunityToken{
  2029  		TokenType:          protobuf.CommunityTokenType_ERC721,
  2030  		CommunityID:        community.IDString(),
  2031  		Address:            "0x001",
  2032  		Name:               "TestTok",
  2033  		Symbol:             "TST",
  2034  		Description:        "Desc",
  2035  		Supply:             &bigint.BigInt{Int: big.NewInt(0)},
  2036  		InfiniteSupply:     true,
  2037  		Transferable:       true,
  2038  		RemoteSelfDestruct: true,
  2039  		ChainID:            1,
  2040  		DeployState:        community_token.Deployed,
  2041  		Base64Image:        "",
  2042  		Decimals:           18,
  2043  		Deployer:           "0x0002",
  2044  		PrivilegesLevel:    community_token.CommunityLevel,
  2045  	}
  2046  
  2047  	err = s.manager.persistence.AddCommunityToken(&token)
  2048  	s.Require().NoError(err)
  2049  
  2050  	// Fill community with missing token
  2051  	err = s.manager.fillMissingCommunityTokens()
  2052  	s.Require().NoError(err)
  2053  
  2054  	community, err = s.manager.GetByID(community.ID())
  2055  	s.Require().NoError(err)
  2056  	s.Require().Len(community.CommunityTokensMetadata(), 1)
  2057  }
  2058  
  2059  func (s *ManagerSuite) TestDetermineChannelsForHRKeysRequest() {
  2060  	request := &requests.CreateCommunity{
  2061  		Name:        "status",
  2062  		Description: "token membership description",
  2063  		Membership:  protobuf.CommunityPermissions_AUTO_ACCEPT,
  2064  	}
  2065  
  2066  	community, err := s.manager.CreateCommunity(request, true)
  2067  	s.Require().NoError(err)
  2068  	s.Require().NotNil(community)
  2069  
  2070  	channel := &protobuf.CommunityChat{
  2071  		Members: map[string]*protobuf.CommunityMember{
  2072  			common.PubkeyToHex(&s.manager.identity.PublicKey): {},
  2073  		},
  2074  	}
  2075  
  2076  	description := community.config.CommunityDescription
  2077  	description.Chats = map[string]*protobuf.CommunityChat{}
  2078  	description.Chats["channel-id"] = channel
  2079  
  2080  	// Simulate channel encrypted
  2081  	_, err = community.UpsertTokenPermission(&protobuf.CommunityTokenPermission{
  2082  		ChatIds: []string{ChatID(community.IDString(), "channel-id")},
  2083  	})
  2084  	s.Require().NoError(err)
  2085  
  2086  	err = generateBloomFiltersForChannels(description, s.manager.identity)
  2087  	s.Require().NoError(err)
  2088  
  2089  	now := int64(1)
  2090  	tenMinutes := int64(10 * 60 * 1000)
  2091  
  2092  	// Member does not have missing encryption keys
  2093  	channels, err := s.manager.determineChannelsForHRKeysRequest(community, now)
  2094  	s.Require().NoError(err)
  2095  	s.Require().Empty(channels)
  2096  
  2097  	// Simulate missing encryption key
  2098  	channel.Members = map[string]*protobuf.CommunityMember{}
  2099  
  2100  	// Channel without prior request should be returned
  2101  	channels, err = s.manager.determineChannelsForHRKeysRequest(community, now)
  2102  	s.Require().NoError(err)
  2103  	s.Require().Len(channels, 1)
  2104  	s.Require().Equal("channel-id", channels[0])
  2105  
  2106  	// Simulate encryption keys request
  2107  	err = s.manager.updateEncryptionKeysRequests(community.ID(), []string{"channel-id"}, now)
  2108  	s.Require().NoError(err)
  2109  
  2110  	// Channel with prior request should not be returned before backoff interval
  2111  	channels, err = s.manager.determineChannelsForHRKeysRequest(community, now)
  2112  	s.Require().NoError(err)
  2113  	s.Require().Len(channels, 0)
  2114  
  2115  	// Channel with prior request should be returned only after backoff interval
  2116  	channels, err = s.manager.determineChannelsForHRKeysRequest(community, now+tenMinutes)
  2117  	s.Require().NoError(err)
  2118  	s.Require().Len(channels, 1)
  2119  	s.Require().Equal("channel-id", channels[0])
  2120  
  2121  	// Simulate multiple encryption keys request
  2122  	err = s.manager.updateEncryptionKeysRequests(community.ID(), []string{"channel-id"}, now+tenMinutes)
  2123  	s.Require().NoError(err)
  2124  	err = s.manager.updateEncryptionKeysRequests(community.ID(), []string{"channel-id"}, now+2*tenMinutes)
  2125  	s.Require().NoError(err)
  2126  
  2127  	// Channel with prior request should not be returned before backoff interval
  2128  	channels, err = s.manager.determineChannelsForHRKeysRequest(community, now+2*tenMinutes)
  2129  	s.Require().NoError(err)
  2130  	s.Require().Len(channels, 0)
  2131  
  2132  	// Channel with prior request should be returned only after backoff interval
  2133  	channels, err = s.manager.determineChannelsForHRKeysRequest(community, now+6*tenMinutes)
  2134  	s.Require().NoError(err)
  2135  	s.Require().Len(channels, 1)
  2136  	s.Require().Equal("channel-id", channels[0])
  2137  
  2138  	// Simulate encryption key being received (it will remove request for given channel)
  2139  	err = s.manager.updateEncryptionKeysRequests(community.ID(), []string{}, now)
  2140  	s.Require().NoError(err)
  2141  
  2142  	// Channel without prior request should be returned
  2143  	channels, err = s.manager.determineChannelsForHRKeysRequest(community, now)
  2144  	s.Require().NoError(err)
  2145  	s.Require().Len(channels, 1)
  2146  	s.Require().Equal("channel-id", channels[0])
  2147  }