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  }