github.com/status-im/status-go@v1.1.0/protocol/messenger_sync_saved_addresses_test.go (about) 1 package protocol 2 3 import ( 4 "context" 5 "crypto/ecdsa" 6 "reflect" 7 "sort" 8 "testing" 9 10 "github.com/stretchr/testify/suite" 11 "go.uber.org/zap" 12 13 "github.com/ethereum/go-ethereum/common" 14 gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" 15 "github.com/status-im/status-go/eth-node/crypto" 16 "github.com/status-im/status-go/eth-node/types" 17 "github.com/status-im/status-go/multiaccounts/settings" 18 "github.com/status-im/status-go/protocol/encryption/multidevice" 19 "github.com/status-im/status-go/protocol/tt" 20 "github.com/status-im/status-go/services/wallet" 21 "github.com/status-im/status-go/waku" 22 ) 23 24 func TestMessengerSyncSavedAddressesSuite(t *testing.T) { 25 suite.Run(t, new(MessengerSyncSavedAddressesSuite)) 26 } 27 28 type MessengerSyncSavedAddressesSuite struct { 29 suite.Suite 30 main *Messenger // main instance of Messenger paired with `other` 31 other *Messenger 32 privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger 33 34 // If one wants to send messages between different instances of Messenger, 35 // a single Waku service should be shared. 36 shh types.Waku 37 38 logger *zap.Logger 39 } 40 41 func (s *MessengerSyncSavedAddressesSuite) SetupTest() { 42 s.logger = tt.MustCreateTestLogger() 43 44 config := waku.DefaultConfig 45 config.MinimumAcceptedPoW = 0 46 shh := waku.New(&config, s.logger) 47 s.shh = gethbridge.NewGethWakuWrapper(shh) 48 s.Require().NoError(shh.Start()) 49 50 s.main = s.newMessenger(s.logger.Named("main")) 51 s.privateKey = s.main.identity 52 53 var err error 54 // Create new device and add main account to 55 s.other, err = newMessengerWithKey(s.shh, s.main.identity, s.logger.Named("other"), nil) 56 s.Require().NoError(err) 57 58 // Pair devices (main and other) 59 imOther := &multidevice.InstallationMetadata{ 60 Name: "other-device", 61 DeviceType: "other-device-type", 62 } 63 err = s.other.SetInstallationMetadata(s.other.installationID, imOther) 64 s.Require().NoError(err) 65 response, err := s.other.SendPairInstallation(context.Background(), nil) 66 s.Require().NoError(err) 67 s.Require().NotNil(response) 68 69 // Wait for the message to reach its destination 70 _, err = WaitOnMessengerResponse( 71 s.main, 72 func(r *MessengerResponse) bool { return len(r.Installations()) > 0 }, 73 "installation not received", 74 ) 75 s.Require().NoError(err) 76 77 err = s.main.EnableInstallation(s.other.installationID) 78 s.Require().NoError(err) 79 } 80 81 func (s *MessengerSyncSavedAddressesSuite) TearDownTest() { 82 TearDownMessenger(&s.Suite, s.main) 83 } 84 85 func (s *MessengerSyncSavedAddressesSuite) newMessenger(logger *zap.Logger) *Messenger { 86 privateKey, err := crypto.GenerateKey() 87 s.Require().NoError(err) 88 89 messenger, err := newMessengerWithKey(s.shh, privateKey, logger, nil) 90 s.Require().NoError(err) 91 92 return messenger 93 } 94 95 // Helpers duplicate of wallet test. Could not import it from saved_addresses_test.go 96 97 func contains[T comparable](container []T, element T, isEqual func(T, T) bool) bool { 98 for _, e := range container { 99 if isEqual(e, element) { 100 return true 101 } 102 } 103 return false 104 } 105 106 func haveSameElements[T comparable](a []T, b []T, isEqual func(T, T) bool) bool { 107 if len(a) != len(b) { 108 return false 109 } 110 for _, v := range a { 111 if !contains(b, v, isEqual) { 112 return false 113 } 114 } 115 return true 116 } 117 118 func savedAddressDataIsEqual(a, b *wallet.SavedAddress) bool { 119 return a.Address == b.Address && a.IsTest == b.IsTest && a.Name == b.Name && 120 a.ENSName == b.ENSName && a.ChainShortNames == b.ChainShortNames && a.ColorID == b.ColorID 121 } 122 123 func (s *MessengerSyncSavedAddressesSuite) TestSyncExistingSavedAddresses() { 124 var isTestChain1 bool = false 125 var isTestChain2 bool = true 126 var testAddress1 = common.Address{1} 127 128 // Add saved addresses to main device 129 sa1 := wallet.SavedAddress{ 130 Address: testAddress1, 131 Name: "TestC1A1", 132 IsTest: isTestChain1, 133 } 134 sa2 := wallet.SavedAddress{ 135 ENSName: "test.ens.eth", 136 Name: "TestC2A1", 137 IsTest: isTestChain2, 138 } 139 140 err := s.main.UpsertSavedAddress(context.Background(), sa1) 141 s.Require().NoError(err) 142 err = s.main.UpsertSavedAddress(context.Background(), sa2) 143 s.Require().NoError(err) 144 145 // Wait and check that saved addresses are synced 146 _, err = WaitOnMessengerResponse( 147 s.other, 148 func(r *MessengerResponse) bool { 149 if len(r.SavedAddresses()) == 2 { 150 sas := r.SavedAddresses() 151 s.Require().True(haveSameElements([]*wallet.SavedAddress{&sa1, &sa2}, []*wallet.SavedAddress{sas[0], sas[1]}, savedAddressDataIsEqual)) 152 return true 153 } 154 return false 155 }, 156 "expected to receive two changes", 157 ) 158 s.Require().NoError(err) 159 160 savedAddresses, err := s.other.savedAddressesManager.GetSavedAddresses() 161 s.Require().NoError(err) 162 s.Require().Equal(2, len(savedAddresses)) 163 s.Require().True(haveSameElements([]*wallet.SavedAddress{&sa1, &sa2}, savedAddresses, savedAddressDataIsEqual)) 164 } 165 166 func (s *MessengerSyncSavedAddressesSuite) TestSyncSavedAddresses() { 167 var isTestChain1 bool = true 168 var testAddress1 = common.Address{1} 169 170 // Add saved addresses to main device 171 sa1 := wallet.SavedAddress{ 172 Address: testAddress1, 173 Name: "TestC1A1", 174 IsTest: isTestChain1, 175 } 176 sa2 := wallet.SavedAddress{ 177 ENSName: "test.ens.eth", 178 Name: "TestC1A2", 179 IsTest: isTestChain1, 180 } 181 182 err := s.main.UpsertSavedAddress(context.Background(), sa1) 183 s.Require().NoError(err) 184 err = s.main.UpsertSavedAddress(context.Background(), sa2) 185 s.Require().NoError(err) 186 187 // Wait and check that saved addresses are synced 188 _, err = WaitOnMessengerResponse( 189 s.other, 190 func(r *MessengerResponse) bool { 191 if len(r.SavedAddresses()) == 2 { 192 sas := r.SavedAddresses() 193 s.Require().True(haveSameElements([]*wallet.SavedAddress{&sa1, &sa2}, []*wallet.SavedAddress{sas[0], sas[1]}, savedAddressDataIsEqual)) 194 return true 195 } 196 return false 197 }, 198 "expected to receive two changes", 199 ) 200 s.Require().NoError(err) 201 202 savedAddresses, err := s.other.savedAddressesManager.GetSavedAddresses() 203 s.Require().NoError(err) 204 s.Require().Equal(2, len(savedAddresses)) 205 s.Require().True(haveSameElements([]*wallet.SavedAddress{&sa1, &sa2}, savedAddresses, savedAddressDataIsEqual)) 206 } 207 208 func (s *MessengerSyncSavedAddressesSuite) requireSavedAddressesEqual(a, b []*wallet.SavedAddress) { 209 sort.Slice(a, func(i, j int) bool { 210 return a[i].Address.Hex() < a[j].Address.Hex() 211 }) 212 sort.Slice(b, func(i, j int) bool { 213 return b[i].Address.Hex() < b[j].Address.Hex() 214 }) 215 s.Require().True(reflect.DeepEqual(a, b)) 216 } 217 218 func (s *MessengerSyncSavedAddressesSuite) testSyncDeletesOfSavedAddresses(testModeMain bool, testModeOther bool) { 219 220 sa1 := &wallet.SavedAddress{ 221 Address: common.Address{1}, 222 Name: "TestC1A1", 223 IsTest: true, 224 } 225 sa2 := &wallet.SavedAddress{ 226 Address: common.Address{2}, 227 Name: "TestC1A2", 228 IsTest: false, 229 } 230 231 err := s.main.settings.SaveSettingField(settings.TestNetworksEnabled, testModeMain) 232 s.Require().NoError(err) 233 err = s.other.settings.SaveSettingField(settings.TestNetworksEnabled, testModeOther) 234 s.Require().NoError(err) 235 236 // Add saved addresses to main device 237 err = s.main.UpsertSavedAddress(context.Background(), *sa1) 238 s.Require().NoError(err) 239 err = s.main.UpsertSavedAddress(context.Background(), *sa2) 240 s.Require().NoError(err) 241 242 // Wait and check that saved addresses are synced 243 { 244 response, err := WaitOnMessengerResponse( 245 s.other, 246 func(r *MessengerResponse) bool { 247 return len(r.SavedAddresses()) == 2 248 }, 249 "expected to receive two changes", 250 ) 251 s.Require().NoError(err) 252 253 otherSavedAddresses := response.SavedAddresses() 254 s.Require().Len(otherSavedAddresses, 2) 255 256 // Check that the UpdateClock was bumped 257 s.Require().GreaterOrEqual(otherSavedAddresses[0].CreatedAt, int64(0)) 258 s.Require().GreaterOrEqual(otherSavedAddresses[1].CreatedAt, int64(0)) 259 s.Require().Greater(otherSavedAddresses[0].UpdateClock, uint64(0)) 260 s.Require().Greater(otherSavedAddresses[1].UpdateClock, uint64(0)) 261 262 // Reset the UpdateClock to 0 for comparison 263 otherSavedAddresses[0].CreatedAt = 0 264 otherSavedAddresses[1].CreatedAt = 0 265 otherSavedAddresses[0].UpdateClock = 0 266 otherSavedAddresses[1].UpdateClock = 0 267 s.requireSavedAddressesEqual([]*wallet.SavedAddress{sa1, sa2}, otherSavedAddresses) 268 269 // Ensure the messenger actually has the saved addresses, not just the response 270 savedAddresses, err := s.other.savedAddressesManager.GetSavedAddresses() 271 s.Require().NoError(err) 272 s.Require().Len(savedAddresses, 2) 273 274 // Reset the UpdateClock to 0 for comparison 275 savedAddresses[0].CreatedAt = 0 276 savedAddresses[1].CreatedAt = 0 277 savedAddresses[0].UpdateClock = 0 278 savedAddresses[1].UpdateClock = 0 279 s.requireSavedAddressesEqual([]*wallet.SavedAddress{sa1, sa2}, savedAddresses) 280 } 281 282 // Delete saved address 1 (test mode = true) and sync with the other device 283 { 284 err = s.main.DeleteSavedAddress(context.Background(), sa1.Address, sa1.IsTest) 285 s.Require().NoError(err) 286 287 // Ensure the removal 288 savedAddresses, err := s.main.savedAddressesManager.GetSavedAddresses() 289 s.Require().NoError(err) 290 s.Require().Len(savedAddresses, 1) 291 sa2.CreatedAt = savedAddresses[0].CreatedAt // force same value 292 sa2.UpdateClock = savedAddresses[0].UpdateClock // force same value 293 s.Require().Equal(sa2, savedAddresses[0]) 294 295 // Wait other device to receive the change 296 response, err := WaitOnMessengerResponse( 297 s.other, 298 func(r *MessengerResponse) bool { 299 return len(r.SavedAddresses()) == 1 300 }, 301 "saved address removal wasn't received", 302 ) 303 s.Require().NoError(err) 304 305 // We expect the delete event to report address, ens, isTest 306 sa := response.SavedAddresses()[0] 307 s.Require().Equal(sa1.Address, sa.Address) 308 s.Require().Equal(sa1.IsTest, sa.IsTest) 309 s.Require().Equal("", sa.Name) 310 311 // Ensure the messenger doesn't return the removed address 312 savedAddresses, err = s.other.savedAddressesManager.GetSavedAddresses() 313 s.Require().NoError(err) 314 s.Require().Len(savedAddresses, 1) 315 savedAddresses[0].CreatedAt = sa2.CreatedAt // force same value 316 s.Require().Equal(sa2, savedAddresses[0]) 317 } 318 319 // Delete saved address 2 (test mode = false) and sync with the other device 320 { 321 err = s.main.DeleteSavedAddress(context.Background(), sa2.Address, sa2.IsTest) 322 s.Require().NoError(err) 323 324 // Ensure the removal 325 savedAddresses, err := s.main.savedAddressesManager.GetSavedAddresses() 326 s.Require().NoError(err) 327 s.Require().Len(savedAddresses, 0) 328 329 // Wait other device to receive the change 330 response, err := WaitOnMessengerResponse( 331 s.other, 332 func(r *MessengerResponse) bool { 333 return len(r.SavedAddresses()) == 1 334 }, 335 "expected to receive one change", 336 ) 337 s.Require().NoError(err) 338 339 sa := response.SavedAddresses()[0] 340 // We expect the deleted event to report address, ens, isTest 341 s.Require().Equal(sa2.Address, sa.Address) 342 s.Require().Equal(sa2.IsTest, sa.IsTest) 343 s.Require().Equal("", sa.Name) 344 345 savedAddresses, err = s.other.savedAddressesManager.GetSavedAddresses() 346 s.Require().NoError(err) 347 s.Require().Len(savedAddresses, 0) 348 } 349 } 350 351 func (s *MessengerSyncSavedAddressesSuite) TestSyncDeletesOfSavedAddresses() { 352 testCases := []struct { 353 Name string 354 TestModeMain bool 355 TestModeOther bool 356 }{ 357 { 358 Name: "same test mode on both devices", 359 TestModeMain: true, 360 TestModeOther: true, 361 }, 362 { 363 Name: "different test mode on devices", 364 TestModeMain: true, 365 TestModeOther: false, 366 }, 367 } 368 369 for _, tc := range testCases { 370 s.Run(tc.Name, func() { 371 s.testSyncDeletesOfSavedAddresses(tc.TestModeMain, tc.TestModeOther) 372 }) 373 } 374 }