github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/hermes_channel_repository_test.go (about) 1 /* 2 * Copyright (C) 2020 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 package pingpong 18 19 import ( 20 "math/big" 21 "sync" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/jinzhu/copier" 28 "github.com/mysteriumnetwork/node/identity" 29 "github.com/mysteriumnetwork/node/mocks" 30 "github.com/mysteriumnetwork/node/session/pingpong/event" 31 "github.com/mysteriumnetwork/payments/client" 32 "github.com/mysteriumnetwork/payments/crypto" 33 "github.com/stretchr/testify/assert" 34 ) 35 36 func TestHermesChannelRepository_Fetch_returns_errors(t *testing.T) { 37 // given 38 id := identity.FromAddress("0x0000000000000000000000000000000000000001") 39 hermesID := common.HexToAddress("0x00000000000000000000000000000000000000002") 40 promiseProvider := &mockHermesPromiseStorage{} 41 channelStatusProvider := &mockProviderChannelStatusProvider{} 42 mockBeneficiaryProvider := &mockBeneficiaryProvider{} 43 mockHermesCaller := &mockHermesCaller{} 44 addrProv := &mockAddressProvider{} 45 46 repo := NewHermesChannelRepository(promiseProvider, channelStatusProvider, mocks.NewEventBus(), mockBeneficiaryProvider, mockHermesCaller, addrProv, signerFactory, &mockEncryptor{}) 47 48 // when 49 channelStatusProvider.channelReturnError = errMock 50 promiseProvider.errToReturn = nil 51 _, err := repo.Fetch(1, id, hermesID) 52 // then 53 assert.Errorf(t, err, "could not get provider channel for %v, hermes %v: %v", mockID, common.Address{}.Hex(), errMock.Error()) 54 55 // when 56 channelStatusProvider.channelReturnError = nil 57 promiseProvider.errToReturn = errMock 58 _, err = repo.Fetch(1, mockID, hermesID) 59 // then 60 assert.Errorf(t, err, "could not get hermes promise for provider %v, hermes %v: %v", mockID, common.Address{}.Hex(), errMock.Error()) 61 62 } 63 64 func TestHermesChannelRepository_Fetch_handles_no_promise(t *testing.T) { 65 // given 66 id := identity.FromAddress("0x0000000000000000000000000000000000000001") 67 hermesID := common.HexToAddress("0x00000000000000000000000000000000000000002") 68 69 expectedPromise := HermesPromise{} 70 promiseProvider := &mockHermesPromiseStorage{ 71 toReturn: expectedPromise, 72 errToReturn: ErrNotFound, 73 } 74 75 expectedChannelStatus := client.ProviderChannel{ 76 Settled: big.NewInt(9000000), 77 Stake: big.NewInt(1000000000000), 78 } 79 channelStatusProvider := &mockProviderChannelStatusProvider{ 80 channelToReturn: expectedChannelStatus, 81 } 82 83 mockBeneficiaryProvider := &mockBeneficiaryProvider{} 84 mockHermesCaller := &mockHermesCaller{} 85 addrProv := &mockAddressProvider{} 86 // when 87 repo := NewHermesChannelRepository(promiseProvider, channelStatusProvider, mocks.NewEventBus(), mockBeneficiaryProvider, mockHermesCaller, addrProv, signerFactory, &mockEncryptor{}) 88 channel, err := repo.Fetch(1, id, hermesID) 89 assert.NoError(t, err) 90 91 // then 92 expectedBalance := new(big.Int).Add(expectedChannelStatus.Stake, expectedChannelStatus.Settled) 93 assert.Equal(t, expectedBalance, channel.balance()) 94 assert.Equal(t, expectedBalance, channel.availableBalance()) 95 } 96 97 func TestHermesChannelRepository_Fetch_takes_promise_into_account(t *testing.T) { 98 // given 99 id := identity.FromAddress("0x0000000000000000000000000000000000000001") 100 hermesID := common.HexToAddress("0x00000000000000000000000000000000000000002") 101 102 expectedPromise := HermesPromise{ 103 Promise: crypto.Promise{Amount: big.NewInt(7000000)}, 104 } 105 promiseProvider := &mockHermesPromiseStorage{ 106 toReturn: expectedPromise, 107 } 108 109 expectedChannelStatus := client.ProviderChannel{ 110 Settled: big.NewInt(9000000), 111 Stake: big.NewInt(1000000000000), 112 } 113 channelStatusProvider := &mockProviderChannelStatusProvider{ 114 channelToReturn: expectedChannelStatus, 115 } 116 mockBeneficiaryProvider := &mockBeneficiaryProvider{} 117 mockHermesCaller := &mockHermesCaller{} 118 addrProv := &mockAddressProvider{} 119 120 // when 121 repo := NewHermesChannelRepository(promiseProvider, channelStatusProvider, mocks.NewEventBus(), mockBeneficiaryProvider, mockHermesCaller, addrProv, signerFactory, &mockEncryptor{}) 122 channel, err := repo.Fetch(1, id, hermesID) 123 assert.NoError(t, err) 124 125 // then 126 added := new(big.Int).Add(expectedChannelStatus.Stake, expectedChannelStatus.Settled) 127 expectedBalance := added.Sub(added, expectedPromise.Promise.Amount) 128 assert.Equal(t, expectedBalance, channel.balance()) 129 assert.Equal(t, new(big.Int).Add(expectedChannelStatus.Stake, expectedChannelStatus.Settled), channel.availableBalance()) 130 } 131 132 func TestHermesChannelRepository_Fetch_publishesEarningChanges(t *testing.T) { 133 // given 134 id := identity.FromAddress("0x0000000000000000000000000000000000000001") 135 hermesID := common.HexToAddress("0x00000000000000000000000000000000000000002") 136 expectedPromise1 := HermesPromise{ 137 ChannelID: "1", 138 Promise: crypto.Promise{Amount: big.NewInt(7000000)}, 139 } 140 expectedPromise2 := HermesPromise{ 141 ChannelID: "1", 142 Promise: crypto.Promise{Amount: big.NewInt(8000000)}, 143 } 144 expectedChannelStatus1 := client.ProviderChannel{ 145 Settled: big.NewInt(9000000), 146 Stake: big.NewInt(1000000000000), 147 } 148 expectedChannelStatus2 := client.ProviderChannel{ 149 Settled: big.NewInt(9000001), 150 Stake: big.NewInt(1000000000001), 151 } 152 153 promiseProvider := &mockHermesPromiseStorage{} 154 channelStatusProvider := &mockProviderChannelStatusProvider{} 155 publisher := mocks.NewEventBus() 156 mockBeneficiaryProvider := &mockBeneficiaryProvider{ 157 b: beneficiaryID, 158 } 159 mockHermesCaller := &mockHermesCaller{} 160 addrProv := &mockAddressProvider{} 161 repo := NewHermesChannelRepository(promiseProvider, channelStatusProvider, publisher, mockBeneficiaryProvider, mockHermesCaller, addrProv, signerFactory, &mockEncryptor{}) 162 163 // when 164 promiseProvider.toReturn = expectedPromise1 165 channelStatusProvider.channelToReturn = expectedChannelStatus1 166 channel, err := repo.Fetch(1, id, hermesID) 167 assert.NoError(t, err) 168 169 // then 170 expectedChannel1 := NewHermesChannel("1", id, hermesID, expectedChannelStatus1, expectedPromise1, beneficiaryID) 171 assert.Equal(t, expectedChannel1, channel) 172 assert.Eventually(t, func() bool { 173 lastEvent, ok := publisher.Pop().(event.AppEventEarningsChanged) 174 if !ok { 175 return false 176 } 177 assert.Equal( 178 t, 179 event.AppEventEarningsChanged{ 180 Identity: id, 181 Previous: event.EarningsDetailed{ 182 Total: event.Earnings{ 183 LifetimeBalance: big.NewInt(0), 184 UnsettledBalance: big.NewInt(0), 185 }, 186 PerHermes: map[common.Address]event.Earnings{}, 187 }, 188 Current: event.EarningsDetailed{ 189 Total: event.Earnings{ 190 LifetimeBalance: expectedChannel1.LifetimeBalance(), 191 UnsettledBalance: expectedChannel1.UnsettledBalance(), 192 }, 193 PerHermes: map[common.Address]event.Earnings{ 194 hermesID: { 195 LifetimeBalance: expectedChannel1.LifetimeBalance(), 196 UnsettledBalance: expectedChannel1.UnsettledBalance(), 197 }, 198 }, 199 }, 200 }, 201 lastEvent, 202 ) 203 return true 204 }, 2*time.Second, 10*time.Millisecond) 205 206 // when 207 promiseProvider.toReturn = expectedPromise2 208 channelStatusProvider.channelToReturn = expectedChannelStatus2 209 channel, err = repo.Fetch(1, id, hermesID) 210 assert.NoError(t, err) 211 212 // then 213 expectedChannel2 := NewHermesChannel("1", id, hermesID, expectedChannelStatus2, expectedPromise2, beneficiaryID) 214 assert.Equal(t, expectedChannel2, channel) 215 assert.Eventually(t, func() bool { 216 lastEvent, ok := publisher.Pop().(event.AppEventEarningsChanged) 217 if !ok { 218 return false 219 } 220 assert.Equal( 221 t, 222 event.AppEventEarningsChanged{ 223 Identity: id, 224 Previous: event.EarningsDetailed{ 225 Total: event.Earnings{ 226 LifetimeBalance: expectedChannel1.LifetimeBalance(), 227 UnsettledBalance: expectedChannel1.UnsettledBalance(), 228 }, 229 PerHermes: map[common.Address]event.Earnings{ 230 hermesID: { 231 LifetimeBalance: expectedChannel1.LifetimeBalance(), 232 UnsettledBalance: expectedChannel1.UnsettledBalance(), 233 }, 234 }, 235 }, 236 Current: event.EarningsDetailed{ 237 Total: event.Earnings{ 238 LifetimeBalance: expectedChannel2.LifetimeBalance(), 239 UnsettledBalance: expectedChannel2.UnsettledBalance(), 240 }, 241 PerHermes: map[common.Address]event.Earnings{ 242 hermesID: { 243 LifetimeBalance: expectedChannel2.LifetimeBalance(), 244 UnsettledBalance: expectedChannel2.UnsettledBalance(), 245 }, 246 }, 247 }, 248 }, 249 lastEvent, 250 ) 251 return true 252 }, 2*time.Second, 10*time.Millisecond) 253 } 254 255 func TestHermesChannelRepository_DataRace(t *testing.T) { 256 // given 257 id := identity.FromAddress("0x0000000000000000000000000000000000000001") 258 hermesID := common.HexToAddress("0x00000000000000000000000000000000000000002") 259 channelID := common.HexToAddress("0x00000000000000000000000000000000000000003") 260 beneficiary := common.HexToAddress("0x144") 261 chainID_ := int64(1) 262 263 promiseProvider := &mockHermesPromiseStorage{} 264 channelStatusProvider := &mockProviderChannelStatusProvider{ 265 channelToReturn: mockProviderChannel, 266 } 267 publisher := mocks.NewEventBus() 268 mockBeneficiaryProvider := &mockBeneficiaryProvider{ 269 b: beneficiary, 270 } 271 mockHermesCaller := &mockHermesCaller{} 272 addrProv := &mockAddressProvider{} 273 repo := NewHermesChannelRepository(promiseProvider, channelStatusProvider, publisher, mockBeneficiaryProvider, mockHermesCaller, addrProv, signerFactory, &mockEncryptor{}) 274 275 var wg sync.WaitGroup 276 277 channels := repo.List(chainID_) 278 active := new(atomic.Bool) 279 active.Store(true) 280 281 promise := HermesPromise{ChannelID: channelID.Hex(), Identity: id, HermesID: hermesID} 282 err := repo.updateChannelWithLatestPromise(chainID_, channelID.Hex(), id, hermesID, promise, true) 283 assert.NoError(t, err) 284 285 channels = repo.List(chainID_) 286 287 wg.Add(3) 288 go func() { 289 defer wg.Done() 290 for i := 0; i < 50; i++ { 291 promise := HermesPromise{ChannelID: channelID.Hex(), Identity: id, HermesID: hermesID} 292 err := repo.updateChannelWithLatestPromise(chainID_, channelID.Hex(), id, hermesID, promise, true) 293 assert.NoError(t, err) 294 } 295 active.Store(false) 296 }() 297 go func() { 298 defer wg.Done() 299 300 for active.Load() == true { 301 // race between Get() and updateChannel() 302 repo.Get(chainID_, id, hermesID) 303 } 304 }() 305 go func() { 306 defer wg.Done() 307 308 var state []HermesChannel 309 for active.Load() == true { 310 if err := copier.CopyWithOption(&state, channels, copier.Option{DeepCopy: true}); err != nil { 311 panic(err) 312 } 313 } 314 }() 315 wg.Wait() 316 } 317 318 func TestHermesChannelRepository_BeneficiaryReset(t *testing.T) { 319 // given 320 id := identity.FromAddress("0x0000000000000000000000000000000000000001") 321 hermesID := common.HexToAddress("0x00000000000000000000000000000000000000002") 322 channelID := common.HexToAddress("0x00000000000000000000000000000000000000003") 323 beneficiary := common.HexToAddress("0x144") 324 325 promiseProvider := &mockHermesPromiseStorage{} 326 channelStatusProvider := &mockProviderChannelStatusProvider{ 327 channelToReturn: mockProviderChannel, 328 } 329 publisher := mocks.NewEventBus() 330 mockBeneficiaryProvider := &mockBeneficiaryProvider{ 331 b: beneficiary, 332 } 333 mockHermesCaller := &mockHermesCaller{} 334 addrProv := &mockAddressProvider{} 335 repo := NewHermesChannelRepository(promiseProvider, channelStatusProvider, publisher, mockBeneficiaryProvider, mockHermesCaller, addrProv, signerFactory, &mockEncryptor{}) 336 337 // when 338 promise := HermesPromise{ChannelID: channelID.Hex(), Identity: id, HermesID: hermesID} 339 err := repo.updateChannelWithLatestPromise(1, channelID.Hex(), id, hermesID, promise, false) 340 assert.NoError(t, err) 341 hermesChannel, exists := repo.Get(1, id, hermesID) 342 343 // then 344 assert.True(t, exists) 345 assert.Equal(t, beneficiary, hermesChannel.Beneficiary) 346 347 // when 348 err = repo.updateChannelWithLatestPromise(1, channelID.Hex(), id, hermesID, promise, false) 349 assert.NoError(t, err) 350 hermesChannel, exists = repo.Get(1, id, hermesID) 351 352 // then 353 assert.True(t, exists) 354 assert.Equal(t, beneficiary, hermesChannel.Beneficiary) 355 } 356 357 type mockBeneficiaryProvider struct { 358 b common.Address 359 } 360 361 func (ms *mockBeneficiaryProvider) GetBeneficiary(identity common.Address) (common.Address, error) { 362 return ms.b, nil 363 } 364 365 var signerFactory = func(id identity.Identity) identity.Signer { 366 return &mockSignerFactory{} 367 } 368 369 type mockSignerFactory struct { 370 } 371 372 func (s *mockSignerFactory) Sign(message []byte) (identity.Signature, error) { 373 return identity.Signature{}, nil 374 }