2021-08-06 15:40:23 +00:00
|
|
|
package communities
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/ecdsa"
|
|
|
|
"database/sql"
|
2023-06-21 11:20:43 +00:00
|
|
|
"math/big"
|
2023-11-14 21:06:33 +00:00
|
|
|
"reflect"
|
2021-08-06 15:40:23 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2024-02-29 09:51:38 +00:00
|
|
|
"github.com/golang/protobuf/proto"
|
2021-08-06 15:40:23 +00:00
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
|
2022-03-08 15:25:00 +00:00
|
|
|
"github.com/status-im/status-go/appdatabase"
|
2021-08-06 15:40:23 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
|
|
"github.com/status-im/status-go/protocol/common"
|
2023-07-07 13:03:37 +00:00
|
|
|
"github.com/status-im/status-go/protocol/communities/token"
|
2024-02-29 09:51:38 +00:00
|
|
|
"github.com/status-im/status-go/protocol/encryption"
|
2021-08-06 15:40:23 +00:00
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
|
|
|
"github.com/status-im/status-go/protocol/sqlite"
|
2023-06-21 11:20:43 +00:00
|
|
|
"github.com/status-im/status-go/services/wallet/bigint"
|
2023-08-11 11:28:45 +00:00
|
|
|
"github.com/status-im/status-go/t/helpers"
|
2024-08-27 13:14:36 +00:00
|
|
|
"github.com/status-im/status-go/wakuv2"
|
2021-08-06 15:40:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestPersistenceSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(PersistenceSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type PersistenceSuite struct {
|
|
|
|
suite.Suite
|
|
|
|
|
2023-11-30 12:25:31 +00:00
|
|
|
db *Persistence
|
|
|
|
identity *ecdsa.PrivateKey
|
2021-08-06 15:40:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) SetupTest() {
|
|
|
|
s.db = nil
|
|
|
|
|
2023-08-11 11:28:45 +00:00
|
|
|
db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "creating sqlite db instance")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
2022-03-08 15:25:00 +00:00
|
|
|
err = sqlite.Migrate(db)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "protocol migrate")
|
2022-03-08 15:25:00 +00:00
|
|
|
|
2023-11-30 12:25:31 +00:00
|
|
|
s.identity, err = crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.db = &Persistence{db: db, recordBundleToCommunity: func(r *CommunityRecordBundle) (*Community, error) {
|
2024-07-01 18:52:57 +00:00
|
|
|
return recordBundleToCommunity(r, s.identity, "", nil, &TimeSourceStub{}, &DescriptionEncryptorMock{}, nil, nil)
|
2023-11-30 12:25:31 +00:00
|
|
|
}}
|
2021-08-06 15:40:23 +00:00
|
|
|
}
|
|
|
|
|
2022-09-20 19:57:39 +00:00
|
|
|
func (s *PersistenceSuite) TestSaveCommunity() {
|
2023-11-30 12:25:31 +00:00
|
|
|
communities, err := s.db.AllCommunities(&s.identity.PublicKey)
|
2022-09-20 19:57:39 +00:00
|
|
|
s.Require().NoError(err)
|
2024-05-10 08:21:07 +00:00
|
|
|
s.Require().Len(communities, 0)
|
2022-09-20 19:57:39 +00:00
|
|
|
|
|
|
|
community := Community{
|
|
|
|
config: &Config{
|
2023-11-30 12:25:31 +00:00
|
|
|
PrivateKey: s.identity,
|
|
|
|
ControlNode: &s.identity.PublicKey,
|
2023-09-21 11:16:05 +00:00
|
|
|
ControlDevice: true,
|
2023-11-30 12:25:31 +00:00
|
|
|
ID: &s.identity.PublicKey,
|
2022-09-20 19:57:39 +00:00
|
|
|
Joined: true,
|
|
|
|
Spectated: true,
|
|
|
|
Verified: true,
|
2023-07-19 12:14:42 +00:00
|
|
|
Muted: true,
|
|
|
|
MuteTill: time.Time{},
|
2022-09-20 19:57:39 +00:00
|
|
|
CommunityDescription: &protobuf.CommunityDescription{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
s.Require().NoError(s.db.SaveCommunity(&community))
|
|
|
|
|
2023-11-30 12:25:31 +00:00
|
|
|
communities, err = s.db.AllCommunities(&s.identity.PublicKey)
|
2022-09-20 19:57:39 +00:00
|
|
|
s.Require().NoError(err)
|
2024-05-10 08:21:07 +00:00
|
|
|
s.Require().Len(communities, 1)
|
|
|
|
s.Equal(types.HexBytes(crypto.CompressPubkey(&s.identity.PublicKey)), communities[0].ID())
|
|
|
|
s.Equal(true, communities[0].Joined())
|
|
|
|
s.Equal(true, communities[0].Spectated())
|
|
|
|
s.Equal(true, communities[0].Verified())
|
|
|
|
s.Equal(true, communities[0].Muted())
|
|
|
|
s.Equal(time.Time{}, communities[0].MuteTill())
|
2022-09-20 19:57:39 +00:00
|
|
|
}
|
|
|
|
|
2021-08-06 15:40:23 +00:00
|
|
|
func (s *PersistenceSuite) TestShouldHandleSyncCommunity() {
|
2023-08-18 11:39:59 +00:00
|
|
|
sc := &protobuf.SyncInstallationCommunity{
|
2021-08-06 15:40:23 +00:00
|
|
|
Id: []byte("0x123456"),
|
|
|
|
Description: []byte("this is a description"),
|
|
|
|
Joined: true,
|
|
|
|
Verified: true,
|
|
|
|
Clock: uint64(time.Now().Unix()),
|
|
|
|
}
|
|
|
|
|
|
|
|
// check an empty db to see if a community should be synced
|
|
|
|
should, err := s.db.ShouldHandleSyncCommunity(sc)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveSyncCommunity")
|
2021-08-06 15:40:23 +00:00
|
|
|
s.True(should)
|
|
|
|
|
|
|
|
// add a new community to the db
|
|
|
|
err = s.db.saveRawCommunityRow(fromSyncCommunityProtobuf(sc))
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "saveRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
rcrs, err := s.db.getAllCommunitiesRaw()
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "should have no error from getAllCommunitiesRaw")
|
2024-05-10 08:21:07 +00:00
|
|
|
s.Len(rcrs, 1, "length of all communities raw should be 1")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// check again to see is the community should be synced
|
|
|
|
sc.Clock--
|
|
|
|
should, err = s.db.ShouldHandleSyncCommunity(sc)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveSyncCommunity")
|
2021-08-06 15:40:23 +00:00
|
|
|
s.False(should)
|
|
|
|
|
|
|
|
// check again to see is the community should be synced
|
|
|
|
sc.Clock++
|
|
|
|
sc.Clock++
|
|
|
|
should, err = s.db.ShouldHandleSyncCommunity(sc)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveSyncCommunity")
|
2021-08-06 15:40:23 +00:00
|
|
|
s.True(should)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestSetSyncClock() {
|
2023-08-18 11:39:59 +00:00
|
|
|
sc := &protobuf.SyncInstallationCommunity{
|
2021-08-06 15:40:23 +00:00
|
|
|
Id: []byte("0x123456"),
|
|
|
|
Description: []byte("this is a description"),
|
|
|
|
Joined: true,
|
|
|
|
Verified: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
// add a new community to the db
|
|
|
|
err := s.db.saveRawCommunityRow(fromSyncCommunityProtobuf(sc))
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "saveRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// retrieve row from db synced_at must be zero
|
|
|
|
rcr, err := s.db.getRawCommunityRow(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "getRawCommunityRow")
|
|
|
|
s.Require().Zero(rcr.SyncedAt, "synced_at must be zero value")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// Set the synced_at value
|
|
|
|
clock := uint64(time.Now().Unix())
|
|
|
|
err = s.db.SetSyncClock(sc.Id, clock)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SetSyncClock")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// Retrieve row from db and check clock matches synced_at value
|
|
|
|
rcr, err = s.db.getRawCommunityRow(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "getRawCommunityRow")
|
|
|
|
s.Require().Equal(clock, rcr.SyncedAt, "synced_at must equal the value of the clock")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// Set Synced At with an older clock value
|
|
|
|
olderClock := clock - uint64(256)
|
|
|
|
err = s.db.SetSyncClock(sc.Id, olderClock)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SetSyncClock")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// Retrieve row from db and check olderClock matches synced_at value
|
|
|
|
rcr, err = s.db.getRawCommunityRow(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "getRawCommunityRow")
|
|
|
|
s.Require().NotEqual(olderClock, rcr.SyncedAt, "synced_at must not equal the value of the olderClock value")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// Set Synced At with a newer clock value
|
|
|
|
newerClock := clock + uint64(512)
|
|
|
|
err = s.db.SetSyncClock(sc.Id, newerClock)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SetSyncClock")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// Retrieve row from db and check olderClock matches synced_at value
|
|
|
|
rcr, err = s.db.getRawCommunityRow(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "getRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
s.Equal(newerClock, rcr.SyncedAt, "synced_at must equal the value of the newerClock value")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestSetPrivateKey() {
|
2023-08-18 11:39:59 +00:00
|
|
|
sc := &protobuf.SyncInstallationCommunity{
|
2021-08-06 15:40:23 +00:00
|
|
|
Id: []byte("0x123456"),
|
|
|
|
Description: []byte("this is a description"),
|
|
|
|
Joined: true,
|
|
|
|
Verified: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
// add a new community to the db with no private key
|
|
|
|
err := s.db.saveRawCommunityRow(fromSyncCommunityProtobuf(sc))
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "saveRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// retrieve row from db, private key must be zero
|
|
|
|
rcr, err := s.db.getRawCommunityRow(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "getRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
s.Zero(rcr.PrivateKey, "private key must be zero value")
|
|
|
|
|
|
|
|
// Set private key
|
2023-11-30 12:25:31 +00:00
|
|
|
err = s.db.SetPrivateKey(sc.Id, s.identity)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SetPrivateKey")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// retrieve row from db again, private key must match the given key
|
|
|
|
rcr, err = s.db.getRawCommunityRow(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "getRawCommunityRow")
|
2023-11-30 12:25:31 +00:00
|
|
|
s.Equal(crypto.FromECDSA(s.identity), rcr.PrivateKey, "private key must match given key")
|
2021-08-06 15:40:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestJoinedAndPendingCommunitiesWithRequests() {
|
|
|
|
clock := uint64(time.Now().Unix())
|
|
|
|
|
|
|
|
// Add a new community that we have joined
|
2023-11-30 12:25:31 +00:00
|
|
|
com := s.makeNewCommunity(s.identity)
|
2021-08-06 15:40:23 +00:00
|
|
|
com.Join()
|
2023-09-21 11:16:05 +00:00
|
|
|
sc, err := com.ToSyncInstallationCommunityProtobuf(clock, nil, nil)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "Community.ToSyncInstallationCommunityProtobuf shouldn't give any error")
|
2021-08-06 15:40:23 +00:00
|
|
|
err = s.db.saveRawCommunityRow(fromSyncCommunityProtobuf(sc))
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "saveRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// Add a new community that we have requested to join, but not yet joined
|
2023-11-30 12:25:31 +00:00
|
|
|
com2 := s.makeNewCommunity(s.identity)
|
2021-08-06 15:40:23 +00:00
|
|
|
err = s.db.SaveCommunity(com2)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveCommunity shouldn't give any error")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
rtj := &RequestToJoin{
|
|
|
|
ID: types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8},
|
2023-11-30 12:25:31 +00:00
|
|
|
PublicKey: common.PubkeyToHex(&s.identity.PublicKey),
|
2021-08-06 15:40:23 +00:00
|
|
|
Clock: clock,
|
|
|
|
CommunityID: com2.ID(),
|
|
|
|
State: RequestToJoinStatePending,
|
|
|
|
}
|
|
|
|
err = s.db.SaveRequestToJoin(rtj)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
2023-11-30 12:25:31 +00:00
|
|
|
comms, err := s.db.JoinedAndPendingCommunitiesWithRequests(&s.identity.PublicKey)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "JoinedAndPendingCommunitiesWithRequests shouldn't give any error")
|
2021-08-06 15:40:23 +00:00
|
|
|
s.Len(comms, 2, "Should have 2 communities")
|
|
|
|
|
|
|
|
for _, comm := range comms {
|
|
|
|
switch comm.IDString() {
|
|
|
|
case com.IDString():
|
|
|
|
s.Len(comm.RequestsToJoin(), 0, "Should have no RequestsToJoin")
|
|
|
|
case com2.IDString():
|
|
|
|
rtjs := comm.RequestsToJoin()
|
|
|
|
s.Len(rtjs, 1, "Should have one RequestsToJoin")
|
|
|
|
s.Equal(rtjs[0], rtj, "RequestToJoin should match the Request stored in the db")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-22 10:10:31 +00:00
|
|
|
func (s *PersistenceSuite) TestSaveRequestToLeave() {
|
|
|
|
rtl := &RequestToLeave{
|
|
|
|
ID: []byte("0x123456"),
|
|
|
|
PublicKey: "0xffffff",
|
|
|
|
Clock: 2,
|
|
|
|
CommunityID: []byte("0x654321"),
|
|
|
|
}
|
|
|
|
|
|
|
|
err := s.db.SaveRequestToLeave(rtl)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-08-22 10:10:31 +00:00
|
|
|
|
|
|
|
// older clocks should not be saved
|
|
|
|
rtl.Clock = 1
|
|
|
|
err = s.db.SaveRequestToLeave(rtl)
|
|
|
|
s.Error(err)
|
|
|
|
}
|
|
|
|
|
2021-08-06 15:40:23 +00:00
|
|
|
func (s *PersistenceSuite) makeNewCommunity(identity *ecdsa.PrivateKey) *Community {
|
|
|
|
comPrivKey, err := crypto.GenerateKey()
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "crypto.GenerateKey shouldn't give any error")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
com, err := New(Config{
|
2024-06-27 15:29:03 +00:00
|
|
|
MemberIdentity: identity,
|
2021-08-06 15:40:23 +00:00
|
|
|
PrivateKey: comPrivKey,
|
2023-10-18 15:04:02 +00:00
|
|
|
ControlNode: &comPrivKey.PublicKey,
|
2023-09-21 11:16:05 +00:00
|
|
|
ControlDevice: true,
|
2021-08-06 15:40:23 +00:00
|
|
|
ID: &comPrivKey.PublicKey,
|
2024-07-01 18:52:57 +00:00
|
|
|
}, &TimeSourceStub{}, &DescriptionEncryptorMock{}, nil)
|
2021-08-06 15:40:23 +00:00
|
|
|
s.NoError(err, "New shouldn't give any error")
|
|
|
|
|
|
|
|
md, err := com.MarshaledDescription()
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "Community.MarshaledDescription shouldn't give any error")
|
2023-07-10 15:35:15 +00:00
|
|
|
com.config.CommunityDescriptionProtocolMessage = md
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
return com
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestGetSyncedRawCommunity() {
|
2023-08-18 11:39:59 +00:00
|
|
|
sc := &protobuf.SyncInstallationCommunity{
|
2021-08-06 15:40:23 +00:00
|
|
|
Id: []byte("0x123456"),
|
|
|
|
Description: []byte("this is a description"),
|
|
|
|
Joined: true,
|
|
|
|
Verified: true,
|
2022-09-20 19:57:39 +00:00
|
|
|
Spectated: true,
|
2021-08-06 15:40:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// add a new community to the db
|
|
|
|
err := s.db.saveRawCommunityRowWithoutSyncedAt(fromSyncCommunityProtobuf(sc))
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "saveRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// retrieve row from db synced_at must be zero
|
|
|
|
rcr, err := s.db.getRawCommunityRow(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "getRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
s.Zero(rcr.SyncedAt, "synced_at must be zero value")
|
|
|
|
|
|
|
|
// retrieve synced row from db, should fail
|
|
|
|
src, err := s.db.getSyncedRawCommunity(sc.Id)
|
|
|
|
s.EqualError(err, sql.ErrNoRows.Error())
|
|
|
|
s.Nil(src)
|
|
|
|
|
|
|
|
// Set the synced_at value
|
|
|
|
clock := uint64(time.Now().Unix())
|
|
|
|
err = s.db.SetSyncClock(sc.Id, clock)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SetSyncClock")
|
2021-08-06 15:40:23 +00:00
|
|
|
|
|
|
|
// retrieve row from db synced_at must not be zero
|
|
|
|
rcr, err = s.db.getRawCommunityRow(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "getRawCommunityRow")
|
2021-08-06 15:40:23 +00:00
|
|
|
s.NotZero(rcr.SyncedAt, "synced_at must be zero value")
|
|
|
|
|
|
|
|
// retrieve synced row from db, should succeed
|
|
|
|
src, err = s.db.getSyncedRawCommunity(sc.Id)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2021-08-06 15:40:23 +00:00
|
|
|
s.NotNil(src)
|
|
|
|
s.Equal(clock, src.SyncedAt)
|
|
|
|
}
|
2022-03-08 15:25:00 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestGetCommunitiesSettings() {
|
|
|
|
settings := []CommunitySettings{
|
|
|
|
{CommunityID: "0x01", HistoryArchiveSupportEnabled: false},
|
|
|
|
{CommunityID: "0x02", HistoryArchiveSupportEnabled: true},
|
|
|
|
{CommunityID: "0x03", HistoryArchiveSupportEnabled: false},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range settings {
|
|
|
|
stg := settings[i]
|
|
|
|
err := s.db.SaveCommunitySettings(stg)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-03-08 15:25:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rst, err := s.db.GetCommunitiesSettings()
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-03-08 15:25:00 +00:00
|
|
|
s.Equal(settings, rst)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestSaveCommunitySettings() {
|
|
|
|
settings := CommunitySettings{CommunityID: "0x01", HistoryArchiveSupportEnabled: false}
|
|
|
|
err := s.db.SaveCommunitySettings(settings)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-03-08 15:25:00 +00:00
|
|
|
rst, err := s.db.GetCommunitiesSettings()
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-03-08 15:25:00 +00:00
|
|
|
s.Equal(1, len(rst))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestDeleteCommunitySettings() {
|
|
|
|
settings := CommunitySettings{CommunityID: "0x01", HistoryArchiveSupportEnabled: false}
|
|
|
|
|
|
|
|
err := s.db.SaveCommunitySettings(settings)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-03-08 15:25:00 +00:00
|
|
|
|
|
|
|
rst, err := s.db.GetCommunitiesSettings()
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-03-08 15:25:00 +00:00
|
|
|
s.Equal(1, len(rst))
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(s.db.DeleteCommunitySettings(types.HexBytes{0x01}))
|
2022-03-08 15:25:00 +00:00
|
|
|
rst2, err := s.db.GetCommunitiesSettings()
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-03-08 15:25:00 +00:00
|
|
|
s.Equal(0, len(rst2))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestUpdateCommunitySettings() {
|
|
|
|
settings := []CommunitySettings{
|
|
|
|
{CommunityID: "0x01", HistoryArchiveSupportEnabled: true},
|
|
|
|
{CommunityID: "0x02", HistoryArchiveSupportEnabled: false},
|
|
|
|
}
|
|
|
|
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(s.db.SaveCommunitySettings(settings[0]))
|
|
|
|
s.Require().NoError(s.db.SaveCommunitySettings(settings[1]))
|
2022-03-08 15:25:00 +00:00
|
|
|
|
|
|
|
settings[0].HistoryArchiveSupportEnabled = true
|
|
|
|
settings[1].HistoryArchiveSupportEnabled = false
|
|
|
|
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(s.db.UpdateCommunitySettings(settings[0]))
|
|
|
|
s.Require().NoError(s.db.UpdateCommunitySettings(settings[1]))
|
2022-03-08 15:25:00 +00:00
|
|
|
|
|
|
|
rst, err := s.db.GetCommunitiesSettings()
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2022-03-08 15:25:00 +00:00
|
|
|
s.Equal(settings, rst)
|
|
|
|
}
|
2023-01-27 13:27:24 +00:00
|
|
|
|
!refactor: introduce `SaveCommunityToken()` and change `AddCommunityToken()`
**This is a breaking change!**
Prior to this commit we had `AddCommunityToken(token *communities,
croppedImage CroppedImage)` that we used to
1. add a `CommunityToken` to the user's database and
2. to create a `CommunityTokenMetadata` from it which is then added to
the community's `CommunityDescription` and published to its members
However, I've then discovered that we need to separate these two things,
such that we can deploy a community token, then add it to the database
only for tracking purposes, **then** add it to the community description
(and propagate to members) once we know that the deploy tx indeed went
through.
To implement this, this commit introduces a new API
`SaveCommunityToken(token *communities.CommunityToken, croppedImage
CroppedImage)` which adds the token to the database only and doesn't
touch the community description.
The `AddCommunityToken` API is then changed that it's exclusively used
for adding an already saved `CommunityToken` to the community
description so it can be published to members. Hence, the signature is
now `AddCommunityToken(communityID string, chainID int, address
string)`, which makes this a breaking change.
Clients that used `AddCommunityToken()` before now need to ensure that
they first call `SaveCommunityToken()` as `AddCommunityToken()` will
fail otherwise.
2023-07-25 11:35:17 +00:00
|
|
|
func (s *PersistenceSuite) TestGetCommunityToken() {
|
|
|
|
tokens, err := s.db.GetCommunityTokens("123")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(tokens, 0)
|
|
|
|
|
2023-07-07 13:03:37 +00:00
|
|
|
tokenERC721 := token.CommunityToken{
|
!refactor: introduce `SaveCommunityToken()` and change `AddCommunityToken()`
**This is a breaking change!**
Prior to this commit we had `AddCommunityToken(token *communities,
croppedImage CroppedImage)` that we used to
1. add a `CommunityToken` to the user's database and
2. to create a `CommunityTokenMetadata` from it which is then added to
the community's `CommunityDescription` and published to its members
However, I've then discovered that we need to separate these two things,
such that we can deploy a community token, then add it to the database
only for tracking purposes, **then** add it to the community description
(and propagate to members) once we know that the deploy tx indeed went
through.
To implement this, this commit introduces a new API
`SaveCommunityToken(token *communities.CommunityToken, croppedImage
CroppedImage)` which adds the token to the database only and doesn't
touch the community description.
The `AddCommunityToken` API is then changed that it's exclusively used
for adding an already saved `CommunityToken` to the community
description so it can be published to members. Hence, the signature is
now `AddCommunityToken(communityID string, chainID int, address
string)`, which makes this a breaking change.
Clients that used `AddCommunityToken()` before now need to ensure that
they first call `SaveCommunityToken()` as `AddCommunityToken()` will
fail otherwise.
2023-07-25 11:35:17 +00:00
|
|
|
CommunityID: "123",
|
|
|
|
TokenType: protobuf.CommunityTokenType_ERC721,
|
|
|
|
Address: "0x123",
|
|
|
|
Name: "StatusToken",
|
|
|
|
Symbol: "STT",
|
|
|
|
Description: "desc",
|
|
|
|
Supply: &bigint.BigInt{Int: big.NewInt(123)},
|
|
|
|
InfiniteSupply: false,
|
|
|
|
Transferable: true,
|
|
|
|
RemoteSelfDestruct: true,
|
|
|
|
ChainID: 1,
|
2023-07-07 13:03:37 +00:00
|
|
|
DeployState: token.InProgress,
|
!refactor: introduce `SaveCommunityToken()` and change `AddCommunityToken()`
**This is a breaking change!**
Prior to this commit we had `AddCommunityToken(token *communities,
croppedImage CroppedImage)` that we used to
1. add a `CommunityToken` to the user's database and
2. to create a `CommunityTokenMetadata` from it which is then added to
the community's `CommunityDescription` and published to its members
However, I've then discovered that we need to separate these two things,
such that we can deploy a community token, then add it to the database
only for tracking purposes, **then** add it to the community description
(and propagate to members) once we know that the deploy tx indeed went
through.
To implement this, this commit introduces a new API
`SaveCommunityToken(token *communities.CommunityToken, croppedImage
CroppedImage)` which adds the token to the database only and doesn't
touch the community description.
The `AddCommunityToken` API is then changed that it's exclusively used
for adding an already saved `CommunityToken` to the community
description so it can be published to members. Hence, the signature is
now `AddCommunityToken(communityID string, chainID int, address
string)`, which makes this a breaking change.
Clients that used `AddCommunityToken()` before now need to ensure that
they first call `SaveCommunityToken()` as `AddCommunityToken()` will
fail otherwise.
2023-07-25 11:35:17 +00:00
|
|
|
Base64Image: "ABCD",
|
2024-05-21 08:51:48 +00:00
|
|
|
TransactionHash: "0x1234",
|
2024-07-02 11:34:18 +00:00
|
|
|
Version: "1.0.0",
|
!refactor: introduce `SaveCommunityToken()` and change `AddCommunityToken()`
**This is a breaking change!**
Prior to this commit we had `AddCommunityToken(token *communities,
croppedImage CroppedImage)` that we used to
1. add a `CommunityToken` to the user's database and
2. to create a `CommunityTokenMetadata` from it which is then added to
the community's `CommunityDescription` and published to its members
However, I've then discovered that we need to separate these two things,
such that we can deploy a community token, then add it to the database
only for tracking purposes, **then** add it to the community description
(and propagate to members) once we know that the deploy tx indeed went
through.
To implement this, this commit introduces a new API
`SaveCommunityToken(token *communities.CommunityToken, croppedImage
CroppedImage)` which adds the token to the database only and doesn't
touch the community description.
The `AddCommunityToken` API is then changed that it's exclusively used
for adding an already saved `CommunityToken` to the community
description so it can be published to members. Hence, the signature is
now `AddCommunityToken(communityID string, chainID int, address
string)`, which makes this a breaking change.
Clients that used `AddCommunityToken()` before now need to ensure that
they first call `SaveCommunityToken()` as `AddCommunityToken()` will
fail otherwise.
2023-07-25 11:35:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = s.db.AddCommunityToken(&tokenERC721)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
token, err := s.db.GetCommunityToken("123", 1, "0x123")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Equal(&tokenERC721, token)
|
|
|
|
}
|
|
|
|
|
2023-01-27 13:27:24 +00:00
|
|
|
func (s *PersistenceSuite) TestGetCommunityTokens() {
|
2023-03-02 17:33:30 +00:00
|
|
|
tokens, err := s.db.GetCommunityTokens("123")
|
2023-01-27 13:27:24 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(tokens, 0)
|
|
|
|
|
2023-07-07 13:03:37 +00:00
|
|
|
tokenERC721 := token.CommunityToken{
|
2023-01-27 13:27:24 +00:00
|
|
|
CommunityID: "123",
|
2023-02-20 11:57:33 +00:00
|
|
|
TokenType: protobuf.CommunityTokenType_ERC721,
|
2023-01-27 13:27:24 +00:00
|
|
|
Address: "0x123",
|
|
|
|
Name: "StatusToken",
|
|
|
|
Symbol: "STT",
|
|
|
|
Description: "desc",
|
2023-06-21 11:20:43 +00:00
|
|
|
Supply: &bigint.BigInt{Int: big.NewInt(123)},
|
2023-01-27 13:27:24 +00:00
|
|
|
InfiniteSupply: false,
|
|
|
|
Transferable: true,
|
|
|
|
RemoteSelfDestruct: true,
|
|
|
|
ChainID: 1,
|
2023-07-07 13:03:37 +00:00
|
|
|
DeployState: token.InProgress,
|
2023-01-27 13:27:24 +00:00
|
|
|
Base64Image: "ABCD",
|
2023-07-18 08:33:45 +00:00
|
|
|
Deployer: "0xDep1",
|
|
|
|
PrivilegesLevel: token.OwnerLevel,
|
2024-05-21 08:51:48 +00:00
|
|
|
TransactionHash: "0x1234",
|
2024-07-02 11:34:18 +00:00
|
|
|
Version: "1.0.0",
|
2023-01-27 13:27:24 +00:00
|
|
|
}
|
|
|
|
|
2023-07-07 13:03:37 +00:00
|
|
|
tokenERC20 := token.CommunityToken{
|
2023-01-27 13:27:24 +00:00
|
|
|
CommunityID: "345",
|
2023-06-14 07:47:54 +00:00
|
|
|
TokenType: protobuf.CommunityTokenType_ERC20,
|
2023-01-27 13:27:24 +00:00
|
|
|
Address: "0x345",
|
|
|
|
Name: "StatusToken",
|
|
|
|
Symbol: "STT",
|
|
|
|
Description: "desc",
|
2023-06-21 11:20:43 +00:00
|
|
|
Supply: &bigint.BigInt{Int: big.NewInt(345)},
|
2023-01-27 13:27:24 +00:00
|
|
|
InfiniteSupply: false,
|
|
|
|
Transferable: true,
|
|
|
|
RemoteSelfDestruct: true,
|
|
|
|
ChainID: 2,
|
2023-07-07 13:03:37 +00:00
|
|
|
DeployState: token.Failed,
|
2023-01-27 13:27:24 +00:00
|
|
|
Base64Image: "QWERTY",
|
2023-06-14 07:47:54 +00:00
|
|
|
Decimals: 21,
|
2023-07-18 08:33:45 +00:00
|
|
|
Deployer: "0xDep2",
|
|
|
|
PrivilegesLevel: token.CommunityLevel,
|
2024-05-21 08:51:48 +00:00
|
|
|
TransactionHash: "0x123456",
|
2024-07-02 11:34:18 +00:00
|
|
|
Version: "2.0.0",
|
2023-01-27 13:27:24 +00:00
|
|
|
}
|
|
|
|
|
2023-06-14 07:47:54 +00:00
|
|
|
err = s.db.AddCommunityToken(&tokenERC721)
|
2023-01-27 13:27:24 +00:00
|
|
|
s.Require().NoError(err)
|
2023-06-14 07:47:54 +00:00
|
|
|
err = s.db.AddCommunityToken(&tokenERC20)
|
2023-01-27 13:27:24 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2023-03-02 17:33:30 +00:00
|
|
|
tokens, err = s.db.GetCommunityTokens("123")
|
2023-01-27 13:27:24 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(tokens, 1)
|
2023-06-14 07:47:54 +00:00
|
|
|
s.Require().Equal(tokenERC721, *tokens[0])
|
2023-01-27 13:27:24 +00:00
|
|
|
|
2023-07-07 13:03:37 +00:00
|
|
|
err = s.db.UpdateCommunityTokenState(1, "0x123", token.Deployed)
|
2023-01-27 13:27:24 +00:00
|
|
|
s.Require().NoError(err)
|
2023-03-02 17:33:30 +00:00
|
|
|
tokens, err = s.db.GetCommunityTokens("123")
|
2023-01-27 13:27:24 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(tokens, 1)
|
2023-07-07 13:03:37 +00:00
|
|
|
s.Require().Equal(token.Deployed, tokens[0].DeployState)
|
2023-06-14 07:47:54 +00:00
|
|
|
|
|
|
|
tokens, err = s.db.GetCommunityTokens("345")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(tokens, 1)
|
|
|
|
s.Require().Equal(tokenERC20, *tokens[0])
|
2023-07-18 08:33:45 +00:00
|
|
|
|
|
|
|
err = s.db.UpdateCommunityTokenAddress(1, "0x123", "0x123-newAddr")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
tokens, err = s.db.GetCommunityTokens("123")
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(tokens, 1)
|
|
|
|
s.Require().Equal("0x123-newAddr", tokens[0].Address)
|
2023-01-27 13:27:24 +00:00
|
|
|
}
|
2023-06-22 06:54:58 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestSaveCheckChannelPermissionResponse() {
|
|
|
|
|
|
|
|
viewAndPostPermissionResults := make(map[string]*PermissionTokenCriteriaResult)
|
|
|
|
viewAndPostPermissionResults["one"] = &PermissionTokenCriteriaResult{
|
|
|
|
Criteria: []bool{true, true, true, true},
|
|
|
|
}
|
|
|
|
viewAndPostPermissionResults["two"] = &PermissionTokenCriteriaResult{
|
|
|
|
Criteria: []bool{false},
|
|
|
|
}
|
|
|
|
chatID := "some-chat-id"
|
|
|
|
communityID := "some-community-id"
|
|
|
|
|
|
|
|
checkChannelPermissionResponse := &CheckChannelPermissionsResponse{
|
|
|
|
ViewOnlyPermissions: &CheckChannelViewOnlyPermissionsResult{
|
|
|
|
Satisfied: true,
|
|
|
|
Permissions: make(map[string]*PermissionTokenCriteriaResult),
|
|
|
|
},
|
|
|
|
ViewAndPostPermissions: &CheckChannelViewAndPostPermissionsResult{
|
|
|
|
Satisfied: true,
|
|
|
|
Permissions: viewAndPostPermissionResults,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
err := s.db.SaveCheckChannelPermissionResponse(communityID, chatID, checkChannelPermissionResponse)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2023-06-22 06:54:58 +00:00
|
|
|
|
|
|
|
responses, err := s.db.GetCheckChannelPermissionResponses(communityID)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err)
|
2023-06-22 06:54:58 +00:00
|
|
|
s.Require().Len(responses, 1)
|
|
|
|
s.Require().NotNil(responses[chatID])
|
|
|
|
s.Require().True(responses[chatID].ViewOnlyPermissions.Satisfied)
|
|
|
|
s.Require().Len(responses[chatID].ViewOnlyPermissions.Permissions, 0)
|
|
|
|
s.Require().True(responses[chatID].ViewAndPostPermissions.Satisfied)
|
|
|
|
s.Require().Len(responses[chatID].ViewAndPostPermissions.Permissions, 2)
|
|
|
|
s.Require().Equal(responses[chatID].ViewAndPostPermissions.Permissions["one"].Criteria, []bool{true, true, true, true})
|
|
|
|
s.Require().Equal(responses[chatID].ViewAndPostPermissions.Permissions["two"].Criteria, []bool{false})
|
|
|
|
}
|
2023-09-20 08:37:46 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestGetCommunityRequestsToJoinWithRevealedAddresses() {
|
|
|
|
clock := uint64(time.Now().Unix())
|
|
|
|
communityID := types.HexBytes{7, 7, 7, 7, 7, 7, 7, 7}
|
|
|
|
revealedAddresses := []string{"address1", "address2", "address3"}
|
|
|
|
chainIds := []uint64{1, 2}
|
|
|
|
|
|
|
|
// No data in database
|
|
|
|
rtjResult, err := s.db.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "GetCommunityRequestsToJoinWithRevealedAddresses shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
s.Require().Len(rtjResult, 0)
|
|
|
|
|
|
|
|
// RTJ with 2 revealed Addresses
|
|
|
|
expectedRtj1 := &RequestToJoin{
|
|
|
|
ID: types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8},
|
2023-11-30 12:25:31 +00:00
|
|
|
PublicKey: common.PubkeyToHex(&s.identity.PublicKey),
|
2023-09-20 08:37:46 +00:00
|
|
|
Clock: clock,
|
|
|
|
CommunityID: communityID,
|
|
|
|
State: RequestToJoinStateAccepted,
|
|
|
|
RevealedAccounts: []*protobuf.RevealedAccount{
|
|
|
|
{
|
|
|
|
Address: revealedAddresses[0],
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Address: revealedAddresses[1],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
err = s.db.SaveRequestToJoin(expectedRtj1)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
|
|
|
|
err = s.db.SaveRequestToJoinRevealedAddresses(expectedRtj1.ID, expectedRtj1.RevealedAccounts)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveRequestToJoinRevealedAddresses shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
|
|
|
|
rtjResult, err = s.db.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "GetCommunityRequestsToJoinWithRevealedAddresses shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
s.Require().Len(rtjResult, 1)
|
|
|
|
s.Require().Equal(expectedRtj1.ID, rtjResult[0].ID)
|
|
|
|
s.Require().Equal(expectedRtj1.PublicKey, rtjResult[0].PublicKey)
|
|
|
|
s.Require().Equal(expectedRtj1.Clock, rtjResult[0].Clock)
|
|
|
|
s.Require().Equal(expectedRtj1.CommunityID, rtjResult[0].CommunityID)
|
|
|
|
s.Require().Len(rtjResult[0].RevealedAccounts, 2)
|
|
|
|
|
|
|
|
for index, account := range rtjResult[0].RevealedAccounts {
|
|
|
|
s.Require().Equal(revealedAddresses[index], account.Address)
|
|
|
|
}
|
|
|
|
|
2023-10-31 14:20:40 +00:00
|
|
|
// RTJ with 1 revealed Address, ChainIds, IsAirdropAddress and Signature
|
|
|
|
signature := []byte("test")
|
2023-09-20 08:37:46 +00:00
|
|
|
expectedRtj2 := &RequestToJoin{
|
|
|
|
ID: types.HexBytes{8, 7, 6, 5, 4, 3, 2, 1},
|
2023-11-30 12:25:31 +00:00
|
|
|
PublicKey: common.PubkeyToHex(&s.identity.PublicKey),
|
2023-09-20 08:37:46 +00:00
|
|
|
Clock: clock,
|
|
|
|
CommunityID: communityID,
|
|
|
|
State: RequestToJoinStateAccepted,
|
|
|
|
RevealedAccounts: []*protobuf.RevealedAccount{
|
|
|
|
{
|
|
|
|
Address: revealedAddresses[2],
|
|
|
|
ChainIds: chainIds,
|
|
|
|
IsAirdropAddress: true,
|
2023-10-31 14:20:40 +00:00
|
|
|
Signature: signature,
|
2023-09-20 08:37:46 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
err = s.db.SaveRequestToJoin(expectedRtj2)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
|
|
|
|
err = s.db.SaveRequestToJoinRevealedAddresses(expectedRtj2.ID, expectedRtj2.RevealedAccounts)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveRequestToJoinRevealedAddresses shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
|
|
|
|
rtjResult, err = s.db.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "GetCommunityRequestsToJoinWithRevealedAddresses shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
s.Require().Len(rtjResult, 2)
|
|
|
|
|
|
|
|
s.Require().Len(rtjResult[1].RevealedAccounts, 1)
|
|
|
|
s.Require().Equal(revealedAddresses[2], rtjResult[1].RevealedAccounts[0].Address)
|
|
|
|
s.Require().Equal(chainIds, rtjResult[1].RevealedAccounts[0].ChainIds)
|
|
|
|
s.Require().Equal(true, rtjResult[1].RevealedAccounts[0].IsAirdropAddress)
|
2023-10-31 14:20:40 +00:00
|
|
|
s.Require().Equal(rtjResult[1].RevealedAccounts[0].Signature, signature)
|
2023-09-20 08:37:46 +00:00
|
|
|
|
|
|
|
// RTJ without RevealedAccounts
|
|
|
|
expectedRtjWithoutRevealedAccounts := &RequestToJoin{
|
|
|
|
ID: types.HexBytes{1, 6, 6, 6, 6, 6, 6, 6},
|
2023-11-30 12:25:31 +00:00
|
|
|
PublicKey: common.PubkeyToHex(&s.identity.PublicKey),
|
2023-09-20 08:37:46 +00:00
|
|
|
Clock: clock,
|
|
|
|
CommunityID: communityID,
|
|
|
|
State: RequestToJoinStateAccepted,
|
|
|
|
}
|
|
|
|
err = s.db.SaveRequestToJoin(expectedRtjWithoutRevealedAccounts)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
|
|
|
|
rtjResult, err = s.db.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "GetCommunityRequestsToJoinWithRevealedAddresses shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
s.Require().Len(rtjResult, 3)
|
|
|
|
|
|
|
|
s.Require().Len(rtjResult[2].RevealedAccounts, 0)
|
|
|
|
|
|
|
|
// RTJ with RevealedAccount but with empty Address
|
|
|
|
expectedRtjWithEmptyAddress := &RequestToJoin{
|
|
|
|
ID: types.HexBytes{2, 6, 6, 6, 6, 6, 6, 6},
|
2023-11-30 12:25:31 +00:00
|
|
|
PublicKey: common.PubkeyToHex(&s.identity.PublicKey),
|
2023-09-20 08:37:46 +00:00
|
|
|
Clock: clock,
|
|
|
|
CommunityID: communityID,
|
|
|
|
State: RequestToJoinStateAccepted,
|
|
|
|
RevealedAccounts: []*protobuf.RevealedAccount{
|
|
|
|
{
|
|
|
|
Address: "",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
err = s.db.SaveRequestToJoin(expectedRtjWithEmptyAddress)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
|
|
|
|
rtjResult, err = s.db.GetCommunityRequestsToJoinWithRevealedAddresses(communityID)
|
2023-07-05 17:35:22 +00:00
|
|
|
s.Require().NoError(err, "GetCommunityRequestsToJoinWithRevealedAddresses shouldn't give any error")
|
2023-09-20 08:37:46 +00:00
|
|
|
s.Require().Len(rtjResult, 4)
|
|
|
|
s.Require().Len(rtjResult[3].RevealedAccounts, 0)
|
|
|
|
}
|
2023-11-14 21:06:33 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestCuratedCommunities() {
|
|
|
|
communities, err := s.db.GetCuratedCommunities()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Empty(communities.ContractCommunities)
|
|
|
|
s.Require().Empty(communities.ContractFeaturedCommunities)
|
|
|
|
|
|
|
|
setCommunities := &CuratedCommunities{
|
|
|
|
ContractCommunities: []string{"x", "d"},
|
|
|
|
ContractFeaturedCommunities: []string{"x"},
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.db.SetCuratedCommunities(setCommunities)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
communities, err = s.db.GetCuratedCommunities()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().True(reflect.DeepEqual(communities, setCommunities))
|
|
|
|
|
|
|
|
setCommunities = &CuratedCommunities{
|
|
|
|
ContractCommunities: []string{"p", "a", "t", "r", "y", "k"},
|
|
|
|
ContractFeaturedCommunities: []string{"p", "k"},
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.db.SetCuratedCommunities(setCommunities)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
communities, err = s.db.GetCuratedCommunities()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().True(reflect.DeepEqual(communities, setCommunities))
|
|
|
|
}
|
2023-11-27 09:54:46 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestGetCommunityRequestToJoinWithRevealedAddresses() {
|
|
|
|
clock := uint64(time.Now().Unix())
|
|
|
|
communityID := types.HexBytes{7, 7, 7, 7, 7, 7, 7, 7}
|
|
|
|
revealedAddresses := []string{"address1", "address2", "address3"}
|
|
|
|
chainIds := []uint64{1, 2}
|
2023-11-30 12:25:31 +00:00
|
|
|
publicKey := common.PubkeyToHex(&s.identity.PublicKey)
|
2023-11-27 09:54:46 +00:00
|
|
|
signature := []byte("test")
|
|
|
|
|
|
|
|
// No data in database
|
2023-11-30 12:25:31 +00:00
|
|
|
_, err := s.db.GetCommunityRequestToJoinWithRevealedAddresses(publicKey, communityID)
|
2023-11-27 09:54:46 +00:00
|
|
|
s.Require().ErrorIs(err, sql.ErrNoRows)
|
|
|
|
|
|
|
|
// RTJ with 2 withoutRevealed Addresses
|
|
|
|
expectedRtj := &RequestToJoin{
|
|
|
|
ID: types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8},
|
|
|
|
PublicKey: publicKey,
|
|
|
|
Clock: clock,
|
|
|
|
CommunityID: communityID,
|
|
|
|
State: RequestToJoinStateAccepted,
|
|
|
|
RevealedAccounts: []*protobuf.RevealedAccount{
|
|
|
|
{
|
|
|
|
Address: revealedAddresses[2],
|
|
|
|
ChainIds: chainIds,
|
|
|
|
IsAirdropAddress: true,
|
|
|
|
Signature: signature,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
err = s.db.SaveRequestToJoin(expectedRtj)
|
|
|
|
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
|
|
|
|
|
|
|
// check that there will be no error if revealed account is absent
|
|
|
|
rtjResult, err := s.db.GetCommunityRequestToJoinWithRevealedAddresses(publicKey, communityID)
|
|
|
|
s.Require().NoError(err, "RevealedAccounts empty, shouldn't give any error")
|
|
|
|
|
|
|
|
s.Require().Len(rtjResult.RevealedAccounts, 0)
|
|
|
|
|
|
|
|
// save revealed accounts for previous request to join
|
|
|
|
err = s.db.SaveRequestToJoinRevealedAddresses(expectedRtj.ID, expectedRtj.RevealedAccounts)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
rtjResult, err = s.db.GetCommunityRequestToJoinWithRevealedAddresses(publicKey, communityID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Equal(expectedRtj.ID, rtjResult.ID)
|
|
|
|
s.Require().Equal(expectedRtj.PublicKey, rtjResult.PublicKey)
|
|
|
|
s.Require().Equal(expectedRtj.Clock, rtjResult.Clock)
|
|
|
|
s.Require().Equal(expectedRtj.CommunityID, rtjResult.CommunityID)
|
|
|
|
s.Require().Len(rtjResult.RevealedAccounts, 1)
|
|
|
|
}
|
2023-12-04 18:20:09 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestAllNonApprovedCommunitiesRequestsToJoin() {
|
|
|
|
// check on empty db
|
|
|
|
result, err := s.db.AllNonApprovedCommunitiesRequestsToJoin()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(result, 0)
|
|
|
|
|
|
|
|
identity, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err, "crypto.GenerateKey shouldn't give any error")
|
|
|
|
|
|
|
|
clock := uint64(time.Now().Unix())
|
|
|
|
|
|
|
|
// add a new community
|
|
|
|
community := s.makeNewCommunity(identity)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// add requests to join to the community
|
|
|
|
allStates := []RequestToJoinState{
|
|
|
|
RequestToJoinStatePending,
|
|
|
|
RequestToJoinStateDeclined,
|
|
|
|
RequestToJoinStateAccepted,
|
|
|
|
RequestToJoinStateCanceled,
|
|
|
|
RequestToJoinStateAcceptedPending,
|
|
|
|
RequestToJoinStateDeclinedPending,
|
|
|
|
RequestToJoinStateAwaitingAddresses,
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range allStates {
|
|
|
|
identity, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
rtj := &RequestToJoin{
|
|
|
|
ID: types.HexBytes{1, 2, 3, 4, 5, 6, 7, byte(i)},
|
|
|
|
PublicKey: common.PubkeyToHex(&identity.PublicKey),
|
|
|
|
Clock: clock,
|
|
|
|
CommunityID: community.ID(),
|
|
|
|
State: allStates[i],
|
|
|
|
}
|
|
|
|
err = s.db.SaveRequestToJoin(rtj)
|
|
|
|
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err = s.db.AllNonApprovedCommunitiesRequestsToJoin()
|
|
|
|
s.Require().NoError(err)
|
2023-12-05 14:50:45 +00:00
|
|
|
s.Require().Len(result, 6) // all except RequestToJoinStateAccepted
|
2023-12-04 18:20:09 +00:00
|
|
|
}
|
2023-12-07 16:27:14 +00:00
|
|
|
|
2023-12-22 12:37:37 +00:00
|
|
|
func (s *PersistenceSuite) TestSaveShardInfo() {
|
|
|
|
communityID := types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8}
|
|
|
|
clock := uint64(1)
|
|
|
|
// get non existing community shard
|
|
|
|
resultShard, err := s.db.GetCommunityShard(communityID)
|
|
|
|
s.Require().Error(err, sql.ErrNoRows)
|
|
|
|
s.Require().Nil(resultShard)
|
|
|
|
|
|
|
|
// shard info is nil
|
|
|
|
err = s.db.SaveCommunityShard(communityID, nil, clock)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// save shard info with the same clock
|
|
|
|
err = s.db.SaveCommunityShard(communityID, nil, clock)
|
|
|
|
s.Require().Error(err, ErrOldShardInfo)
|
|
|
|
|
|
|
|
resultShard, err = s.db.GetCommunityShard(communityID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Nil(resultShard)
|
|
|
|
|
|
|
|
// not nil shard
|
2024-08-27 13:14:36 +00:00
|
|
|
expectedShard := &wakuv2.Shard{
|
2023-12-22 12:37:37 +00:00
|
|
|
Cluster: 1,
|
|
|
|
Index: 2,
|
|
|
|
}
|
|
|
|
|
|
|
|
// save shard info with the same clock and check that data was not modified
|
|
|
|
err = s.db.SaveCommunityShard(communityID, expectedShard, clock)
|
|
|
|
s.Require().Error(err, ErrOldShardInfo)
|
|
|
|
resultShard, err = s.db.GetCommunityShard(communityID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Nil(resultShard)
|
|
|
|
|
|
|
|
// update the clock and save the shard info
|
|
|
|
clock += clock
|
|
|
|
err = s.db.SaveCommunityShard(communityID, expectedShard, clock)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
resultShard, err = s.db.GetCommunityShard(communityID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(resultShard)
|
|
|
|
s.Require().Equal(expectedShard, resultShard)
|
|
|
|
|
|
|
|
// check shard deleting
|
|
|
|
err = s.db.DeleteCommunityShard(communityID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
resultShard, err = s.db.GetCommunityShard(communityID)
|
|
|
|
s.Require().Error(err, sql.ErrNoRows)
|
|
|
|
s.Require().Nil(resultShard)
|
|
|
|
}
|
2024-01-05 17:09:38 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestGetCommunityToValidateByID() {
|
|
|
|
communityID := types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8}
|
|
|
|
|
|
|
|
result, err := s.db.getCommunityToValidateByID(communityID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(result, 0)
|
|
|
|
}
|
2024-02-19 09:52:22 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestProcessedCommunityEvents() {
|
|
|
|
community := types.HexBytes{1}
|
|
|
|
events, err := s.db.GetAppliedCommunityEvents(community)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Empty(events)
|
|
|
|
|
|
|
|
err = s.db.UpsertAppliedCommunityEvents(community, map[string]uint64{"a": 1, "b": 10})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
events, err = s.db.GetAppliedCommunityEvents(community)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(events, 2)
|
|
|
|
s.Require().True(reflect.DeepEqual(events, map[string]uint64{"a": 1, "b": 10}))
|
|
|
|
|
|
|
|
err = s.db.UpsertAppliedCommunityEvents(community, map[string]uint64{"a": 2, "b": 8, "c": 1})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
events, err = s.db.GetAppliedCommunityEvents(community)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(events, 3)
|
|
|
|
s.Require().True(reflect.DeepEqual(events, map[string]uint64{"a": 2, "b": 10, "c": 1}))
|
|
|
|
}
|
2024-02-29 09:51:38 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestDecryptedCommunityCache() {
|
|
|
|
communityDescription := &protobuf.CommunityDescription{
|
|
|
|
Clock: 1000,
|
|
|
|
}
|
|
|
|
keyID1 := []byte("key-id-1")
|
|
|
|
keyID2 := []byte("key-id-2")
|
|
|
|
missingKeys := []*CommunityPrivateDataFailedToDecrypt{
|
|
|
|
{KeyID: keyID1},
|
|
|
|
{KeyID: keyID2},
|
|
|
|
}
|
|
|
|
communityID := []byte("id")
|
|
|
|
err := s.db.SaveDecryptedCommunityDescription(communityID, missingKeys, communityDescription)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Can be retrieved
|
|
|
|
retrievedCommunity, err := s.db.GetDecryptedCommunityDescription(communityID, 1000)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().True(proto.Equal(communityDescription, retrievedCommunity))
|
|
|
|
|
|
|
|
// Retrieving a random one doesn't throw an error
|
|
|
|
retrievedCommunity, err = s.db.GetDecryptedCommunityDescription([]byte("non-existent-id"), 1000)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Nil(retrievedCommunity)
|
|
|
|
|
|
|
|
// Retrieving a random one doesn't throw an error
|
|
|
|
retrievedCommunity, err = s.db.GetDecryptedCommunityDescription(communityID, 999)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Nil(retrievedCommunity)
|
|
|
|
|
|
|
|
// invalidating the cache
|
|
|
|
err = s.db.InvalidateDecryptedCommunityCacheForKeys([]*encryption.HashRatchetInfo{{KeyID: keyID1}})
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// community cannot be retrieved anymore
|
|
|
|
retrievedCommunity, err = s.db.GetDecryptedCommunityDescription(communityID, 1000)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Nil(retrievedCommunity)
|
|
|
|
|
|
|
|
// make sure everything is cleaned up
|
|
|
|
|
|
|
|
qr := s.db.db.QueryRow("SELECT COUNT(*) FROM encrypted_community_description_missing_keys")
|
|
|
|
|
|
|
|
var count int
|
|
|
|
|
|
|
|
err = qr.Scan(&count)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Equal(count, 0)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestDecryptedCommunityCacheClock() {
|
|
|
|
communityDescription := &protobuf.CommunityDescription{
|
|
|
|
Clock: 1000,
|
|
|
|
}
|
|
|
|
keyID1 := []byte("key-id-1")
|
|
|
|
keyID2 := []byte("key-id-2")
|
|
|
|
keyID3 := []byte("key-id-3")
|
|
|
|
|
|
|
|
missingKeys := []*CommunityPrivateDataFailedToDecrypt{
|
|
|
|
{KeyID: keyID1},
|
|
|
|
{KeyID: keyID2},
|
|
|
|
}
|
|
|
|
communityID := []byte("id")
|
|
|
|
err := s.db.SaveDecryptedCommunityDescription(communityID, missingKeys, communityDescription)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Can be retrieved
|
|
|
|
retrievedCommunity, err := s.db.GetDecryptedCommunityDescription(communityID, 1000)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().True(proto.Equal(communityDescription, retrievedCommunity))
|
|
|
|
|
|
|
|
// Save an earlier community
|
|
|
|
communityDescription.Clock = 999
|
|
|
|
err = s.db.SaveDecryptedCommunityDescription(communityID, missingKeys, communityDescription)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// The old one should be retrieved
|
|
|
|
retrievedCommunity, err = s.db.GetDecryptedCommunityDescription(communityID, 1000)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().NotNil(retrievedCommunity)
|
|
|
|
s.Require().Equal(uint64(1000), retrievedCommunity.Clock)
|
|
|
|
|
|
|
|
// Save a later community, with a single key
|
|
|
|
missingKeys = []*CommunityPrivateDataFailedToDecrypt{
|
|
|
|
{KeyID: keyID3},
|
|
|
|
}
|
|
|
|
|
|
|
|
communityDescription.Clock = 1001
|
|
|
|
err = s.db.SaveDecryptedCommunityDescription(communityID, missingKeys, communityDescription)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// The new one should be retrieved
|
|
|
|
retrievedCommunity, err = s.db.GetDecryptedCommunityDescription(communityID, 1001)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Equal(uint64(1001), retrievedCommunity.Clock)
|
|
|
|
|
|
|
|
// Make sure the previous two are cleaned up and there's only one left
|
|
|
|
qr := s.db.db.QueryRow("SELECT COUNT(*) FROM encrypted_community_description_missing_keys")
|
|
|
|
|
|
|
|
var count int
|
|
|
|
|
|
|
|
err = qr.Scan(&count)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Equal(count, 1)
|
|
|
|
}
|
2024-05-17 16:15:39 +00:00
|
|
|
|
|
|
|
func (s *PersistenceSuite) TestGetCommunityRequestsToJoinRevealedAddresses() {
|
|
|
|
clock := uint64(time.Now().Unix())
|
|
|
|
communityID := types.HexBytes{7, 7, 7, 7, 7, 7, 7, 7}
|
|
|
|
revealedAddress := "address1"
|
|
|
|
chainIds := []uint64{1, 2}
|
|
|
|
publicKey := common.PubkeyToHex(&s.identity.PublicKey)
|
|
|
|
signature := []byte("test")
|
|
|
|
|
|
|
|
// No data in database
|
|
|
|
accounts, err := s.db.GetCommunityRequestsToJoinRevealedAddresses(communityID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
_, exists := accounts[publicKey]
|
|
|
|
s.Require().False(exists)
|
|
|
|
|
|
|
|
expectedRtj := &RequestToJoin{
|
|
|
|
ID: types.HexBytes{1, 2, 3, 4, 5, 6, 7, 8},
|
|
|
|
PublicKey: publicKey,
|
|
|
|
Clock: clock,
|
|
|
|
CommunityID: communityID,
|
|
|
|
State: RequestToJoinStateAccepted,
|
|
|
|
RevealedAccounts: []*protobuf.RevealedAccount{
|
|
|
|
{
|
|
|
|
Address: revealedAddress,
|
|
|
|
ChainIds: chainIds,
|
|
|
|
IsAirdropAddress: true,
|
|
|
|
Signature: signature,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Request to join was stored without revealed account
|
|
|
|
err = s.db.SaveRequestToJoin(expectedRtj)
|
|
|
|
s.Require().NoError(err, "SaveRequestToJoin shouldn't give any error")
|
|
|
|
|
|
|
|
// revealed account is absent
|
|
|
|
accounts, err = s.db.GetCommunityRequestsToJoinRevealedAddresses(communityID)
|
|
|
|
s.Require().NoError(err, "RevealedAccounts empty, shouldn't give any error")
|
|
|
|
|
|
|
|
_, exists = accounts[publicKey]
|
|
|
|
s.Require().False(exists)
|
|
|
|
|
|
|
|
// save revealed accounts for the previous request to join
|
|
|
|
err = s.db.SaveRequestToJoinRevealedAddresses(expectedRtj.ID, expectedRtj.RevealedAccounts)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
accounts, err = s.db.GetCommunityRequestsToJoinRevealedAddresses(communityID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
memberAccounts, exists := accounts[publicKey]
|
|
|
|
s.Require().True(exists)
|
|
|
|
s.Require().Len(memberAccounts, 1)
|
|
|
|
}
|