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  }