github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/invoice_tracker_test.go (about)

     1  /*
     2   * Copyright (C) 2019 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  
    18  package pingpong
    19  
    20  import (
    21  	"encoding/hex"
    22  	"math/big"
    23  	"os"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/mysteriumnetwork/node/core/storage/boltdb"
    30  	"github.com/mysteriumnetwork/node/identity"
    31  	"github.com/mysteriumnetwork/node/market"
    32  	"github.com/mysteriumnetwork/node/mocks"
    33  	"github.com/mysteriumnetwork/node/session"
    34  	"github.com/mysteriumnetwork/node/session/mbtime"
    35  	"github.com/mysteriumnetwork/payments/crypto"
    36  	"github.com/mysteriumnetwork/payments/observer"
    37  	"github.com/pkg/errors"
    38  	"github.com/stretchr/testify/assert"
    39  )
    40  
    41  const (
    42  	mockRegistryAddress       = "0xE6b3a5c92e7c1f9543A0aEE9A93fE2F6B584c1f7"
    43  	mockHermesAddress         = "0xf28DB7aDf64A2811202B149aa4733A1FB9100e5c"
    44  	mockChannelImplementation = "0xa26b684d8dBa935DD34544FBd3Ab4d7FDe1C4D07"
    45  )
    46  
    47  type MockPeerInvoiceSender struct {
    48  	mockError     error
    49  	chanToWriteTo chan crypto.Invoice
    50  }
    51  
    52  func (mpis *MockPeerInvoiceSender) Send(invoice crypto.Invoice) error {
    53  	if mpis.chanToWriteTo != nil {
    54  		mpis.chanToWriteTo <- invoice
    55  	}
    56  	return mpis.mockError
    57  }
    58  
    59  type mockHermesCaller struct {
    60  	errToReturn error
    61  }
    62  
    63  func (mac *mockHermesCaller) RequestPromise(rp RequestPromise) (crypto.Promise, error) {
    64  	return crypto.Promise{}, mac.errToReturn
    65  }
    66  
    67  func (mac *mockHermesCaller) PayAndSettle(rp RequestPromise) (crypto.Promise, error) {
    68  	return crypto.Promise{}, mac.errToReturn
    69  }
    70  
    71  func (mac *mockHermesCaller) RevealR(r string, provider string, agreementID *big.Int) error {
    72  	return mac.errToReturn
    73  }
    74  
    75  func (mac *mockHermesCaller) UpdatePromiseFee(promise crypto.Promise, newFee *big.Int) (crypto.Promise, error) {
    76  	return promise, nil
    77  }
    78  
    79  func (mac *mockHermesCaller) GetConsumerData(chainID int64, id string, cacheTime time.Duration) (HermesUserInfo, error) {
    80  	return HermesUserInfo{}, nil
    81  }
    82  
    83  func (mac *mockHermesCaller) GetProviderData(chainID int64, id string) (HermesUserInfo, error) {
    84  	return HermesUserInfo{}, nil
    85  }
    86  
    87  func (mac *mockHermesCaller) SyncProviderPromise(promise crypto.Promise, signer identity.Signer) error {
    88  	return nil
    89  }
    90  
    91  func (mac *mockHermesCaller) RefreshLatestProviderPromise(chainID int64, id string, hashlock, recoveryData []byte, signer identity.Signer) (crypto.Promise, error) {
    92  	return crypto.Promise{}, nil
    93  }
    94  
    95  func Test_InvoiceTracker_Start_Stop(t *testing.T) {
    96  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
    97  	assert.Nil(t, err)
    98  	defer os.RemoveAll(dir)
    99  
   100  	ks := identity.NewMockKeystore()
   101  	acc, err := ks.NewAccount("")
   102  	assert.Nil(t, err)
   103  
   104  	mockSender := &MockPeerInvoiceSender{
   105  		chanToWriteTo: make(chan crypto.Invoice, 10),
   106  	}
   107  
   108  	exchangeMessageChan := make(chan crypto.ExchangeMessage)
   109  	bolt, err := boltdb.NewStorage(dir)
   110  	assert.Nil(t, err)
   111  	defer bolt.Close()
   112  
   113  	tracker := session.NewTracker(mbtime.Now)
   114  	invoiceStorage := NewProviderInvoiceStorage(NewInvoiceStorage(bolt))
   115  	deps := InvoiceTrackerDeps{
   116  		AgreedPrice:                *market.NewPrice(600, 0),
   117  		Peer:                       identity.FromAddress("some peer"),
   118  		PeerInvoiceSender:          mockSender,
   119  		EventBus:                   mocks.NewEventBus(),
   120  		InvoiceStorage:             invoiceStorage,
   121  		TimeTracker:                &tracker,
   122  		ChargePeriod:               time.Nanosecond,
   123  		ChargePeriodLeeway:         15 * time.Minute,
   124  		LimitChargePeriod:          time.Nanosecond,
   125  		LimitNotPaidInvoice:        big.NewInt(0),
   126  		ExchangeMessageChan:        exchangeMessageChan,
   127  		ExchangeMessageWaitTimeout: time.Second,
   128  		ProviderID:                 identity.FromAddress(acc.Address.Hex()),
   129  		ConsumersHermesID:          acc.Address,
   130  		AddressProvider:            &mockAddressProvider{},
   131  		HermesStatusChecker:        &mockHermesStatusChecker{statusToReturn: HermesStatus{IsActive: true}},
   132  	}
   133  	invoiceTracker := NewInvoiceTracker(deps)
   134  
   135  	go func() {
   136  		time.Sleep(time.Nanosecond * 10)
   137  		invoiceTracker.Stop()
   138  	}()
   139  
   140  	err = invoiceTracker.Start()
   141  	assert.Nil(t, err)
   142  }
   143  
   144  func Test_InvoiceTracker_Start_RefusesLargeFee(t *testing.T) {
   145  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
   146  	assert.Nil(t, err)
   147  	defer os.RemoveAll(dir)
   148  
   149  	ks := identity.NewMockKeystore()
   150  	acc, err := ks.NewAccount("")
   151  	assert.Nil(t, err)
   152  
   153  	mockSender := &MockPeerInvoiceSender{
   154  		chanToWriteTo: make(chan crypto.Invoice, 10),
   155  	}
   156  
   157  	exchangeMessageChan := make(chan crypto.ExchangeMessage)
   158  	bolt, err := boltdb.NewStorage(dir)
   159  	assert.Nil(t, err)
   160  	defer bolt.Close()
   161  
   162  	tracker := session.NewTracker(mbtime.Now)
   163  	invoiceStorage := NewProviderInvoiceStorage(NewInvoiceStorage(bolt))
   164  	deps := InvoiceTrackerDeps{
   165  		AgreedPrice:                *market.NewPrice(600, 0),
   166  		Peer:                       identity.FromAddress("some peer"),
   167  		PeerInvoiceSender:          mockSender,
   168  		InvoiceStorage:             invoiceStorage,
   169  		TimeTracker:                &tracker,
   170  		ChargePeriod:               time.Nanosecond,
   171  		LimitChargePeriod:          time.Nanosecond,
   172  		LimitNotPaidInvoice:        big.NewInt(0),
   173  		ExchangeMessageChan:        exchangeMessageChan,
   174  		ExchangeMessageWaitTimeout: time.Second,
   175  		ProviderID:                 identity.FromAddress(acc.Address.Hex()),
   176  		ConsumersHermesID:          acc.Address,
   177  		AddressProvider:            &mockAddressProvider{},
   178  		EventBus:                   mocks.NewEventBus(),
   179  		MaxAllowedHermesFee:        1500,
   180  		HermesStatusChecker:        &mockHermesStatusChecker{statusToReturn: HermesStatus{IsActive: true, Fee: 1501}},
   181  	}
   182  	invoiceTracker := NewInvoiceTracker(deps)
   183  
   184  	go func() {
   185  		time.Sleep(time.Nanosecond * 10)
   186  		invoiceTracker.Stop()
   187  	}()
   188  
   189  	err = invoiceTracker.Start()
   190  	assert.Equal(t, ErrHermesFeeTooLarge, err)
   191  }
   192  
   193  func Test_InvoiceTracker_Start_BubblesHermesCheckError(t *testing.T) {
   194  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
   195  	assert.Nil(t, err)
   196  	defer os.RemoveAll(dir)
   197  
   198  	ks := identity.NewMockKeystore()
   199  	acc, err := ks.NewAccount("")
   200  	assert.Nil(t, err)
   201  
   202  	mockSender := &MockPeerInvoiceSender{
   203  		chanToWriteTo: make(chan crypto.Invoice, 10),
   204  	}
   205  
   206  	exchangeMessageChan := make(chan crypto.ExchangeMessage)
   207  	bolt, err := boltdb.NewStorage(dir)
   208  	assert.Nil(t, err)
   209  	defer bolt.Close()
   210  
   211  	mockErr := errors.New("explosions everywhere")
   212  	tracker := session.NewTracker(mbtime.Now)
   213  	invoiceStorage := NewProviderInvoiceStorage(NewInvoiceStorage(bolt))
   214  	NewHermesPromiseStorage(bolt)
   215  	deps := InvoiceTrackerDeps{
   216  		AgreedPrice:                *market.NewPrice(600, 0),
   217  		Peer:                       identity.FromAddress("some peer"),
   218  		PeerInvoiceSender:          mockSender,
   219  		InvoiceStorage:             invoiceStorage,
   220  		TimeTracker:                &tracker,
   221  		ChargePeriod:               time.Nanosecond,
   222  		ChargePeriodLeeway:         15 * time.Minute,
   223  		LimitChargePeriod:          time.Nanosecond,
   224  		LimitNotPaidInvoice:        big.NewInt(0),
   225  		ExchangeMessageChan:        exchangeMessageChan,
   226  		ExchangeMessageWaitTimeout: time.Second,
   227  		ProviderID:                 identity.FromAddress(acc.Address.Hex()),
   228  		ConsumersHermesID:          acc.Address,
   229  		AddressProvider:            &mockAddressProvider{},
   230  		EventBus:                   mocks.NewEventBus(),
   231  		HermesStatusChecker:        &mockHermesStatusChecker{errToReturn: mockErr},
   232  	}
   233  	invoiceTracker := NewInvoiceTracker(deps)
   234  
   235  	go func() {
   236  		time.Sleep(time.Nanosecond * 10)
   237  		invoiceTracker.Stop()
   238  	}()
   239  
   240  	err = invoiceTracker.Start()
   241  	assert.Equal(t, errors.Wrap(mockErr, "could not check hermes status").Error(), err.Error())
   242  }
   243  
   244  func Test_InvoiceTracker_BubblesErrors(t *testing.T) {
   245  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
   246  	assert.Nil(t, err)
   247  	defer os.RemoveAll(dir)
   248  
   249  	ks := identity.NewMockKeystore()
   250  	acc, err := ks.NewAccount("")
   251  	assert.Nil(t, err)
   252  
   253  	mockSender := &MockPeerInvoiceSender{
   254  		chanToWriteTo: make(chan crypto.Invoice, 10),
   255  	}
   256  
   257  	exchangeMessageChan := make(chan crypto.ExchangeMessage)
   258  	bolt, err := boltdb.NewStorage(dir)
   259  	assert.Nil(t, err)
   260  	defer bolt.Close()
   261  
   262  	tracker := session.NewTracker(mbtime.Now)
   263  	invoiceStorage := NewProviderInvoiceStorage(NewInvoiceStorage(bolt))
   264  	deps := InvoiceTrackerDeps{
   265  		AgreedPrice:                *market.NewPrice(600, 0),
   266  		Peer:                       identity.FromAddress("some peer"),
   267  		PeerInvoiceSender:          mockSender,
   268  		InvoiceStorage:             invoiceStorage,
   269  		TimeTracker:                &tracker,
   270  		LimitChargePeriod:          time.Nanosecond,
   271  		LimitNotPaidInvoice:        big.NewInt(0),
   272  		ChargePeriod:               time.Millisecond,
   273  		ChargePeriodLeeway:         15 * time.Minute,
   274  		ExchangeMessageChan:        exchangeMessageChan,
   275  		ExchangeMessageWaitTimeout: time.Second,
   276  		ProviderID:                 identity.FromAddress(acc.Address.Hex()),
   277  		ConsumersHermesID:          acc.Address,
   278  		AddressProvider:            &mockAddressProvider{},
   279  		EventBus:                   mocks.NewEventBus(),
   280  		HermesStatusChecker:        &mockHermesStatusChecker{statusToReturn: HermesStatus{IsActive: true}},
   281  	}
   282  	invoiceTracker := NewInvoiceTracker(deps)
   283  	defer invoiceTracker.Stop()
   284  
   285  	errChan := make(chan error)
   286  	go func() { errChan <- invoiceTracker.Start() }()
   287  
   288  	invoice := <-mockSender.chanToWriteTo
   289  	b, err := hex.DecodeString(invoice.Hashlock)
   290  	assert.NoError(t, err)
   291  	exchangeMessageChan <- crypto.ExchangeMessage{
   292  		Promise: crypto.Promise{
   293  			Hashlock: b,
   294  		},
   295  	}
   296  
   297  	err = <-errChan
   298  	assert.Error(t, err)
   299  }
   300  
   301  func Test_InvoiceTracker_SendsInvoice(t *testing.T) {
   302  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
   303  	assert.Nil(t, err)
   304  	defer os.RemoveAll(dir)
   305  
   306  	ks := identity.NewMockKeystore()
   307  	acc, err := ks.NewAccount("")
   308  	assert.Nil(t, err)
   309  	mockSender := &MockPeerInvoiceSender{
   310  		chanToWriteTo: make(chan crypto.Invoice, 10),
   311  	}
   312  
   313  	exchangeMessageChan := make(chan crypto.ExchangeMessage)
   314  	bolt, err := boltdb.NewStorage(dir)
   315  	assert.Nil(t, err)
   316  	defer bolt.Close()
   317  
   318  	tracker := session.NewTracker(mbtime.Now)
   319  	invoiceStorage := NewProviderInvoiceStorage(NewInvoiceStorage(bolt))
   320  	deps := InvoiceTrackerDeps{
   321  		AgreedPrice:                *market.NewPrice(60000000000000, 0),
   322  		Peer:                       identity.FromAddress("some peer"),
   323  		PeerInvoiceSender:          mockSender,
   324  		InvoiceStorage:             invoiceStorage,
   325  		TimeTracker:                &tracker,
   326  		LimitChargePeriod:          time.Nanosecond,
   327  		ChargePeriod:               time.Nanosecond,
   328  		LimitNotPaidInvoice:        big.NewInt(0),
   329  		MaxNotPaidInvoice:          big.NewInt(0),
   330  		ChargePeriodLeeway:         15 * time.Minute,
   331  		ExchangeMessageChan:        exchangeMessageChan,
   332  		ExchangeMessageWaitTimeout: time.Second,
   333  		ProviderID:                 identity.FromAddress(acc.Address.Hex()),
   334  		ConsumersHermesID:          acc.Address,
   335  		AddressProvider:            &mockAddressProvider{},
   336  		HermesStatusChecker:        &mockHermesStatusChecker{statusToReturn: HermesStatus{IsActive: true}},
   337  		EventBus:                   mocks.NewEventBus(),
   338  	}
   339  	invoiceTracker := NewInvoiceTracker(deps)
   340  	defer invoiceTracker.Stop()
   341  
   342  	errChan := make(chan error)
   343  	go func() { errChan <- invoiceTracker.Start() }()
   344  
   345  	invoice := <-mockSender.chanToWriteTo
   346  	assert.True(t, invoice.AgreementTotal.Cmp(new(big.Int)) > 0)
   347  	assert.Len(t, invoice.Hashlock, 64)
   348  	assert.Equal(t, strings.ToLower(acc.Address.Hex()), strings.ToLower(invoice.Provider))
   349  
   350  	invoiceTracker.Stop()
   351  	assert.NoError(t, <-errChan)
   352  }
   353  
   354  func Test_InvoiceTracker_FirstInvoice_Has_Static_Value(t *testing.T) {
   355  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
   356  	assert.Nil(t, err)
   357  	defer os.RemoveAll(dir)
   358  
   359  	ks := identity.NewMockKeystore()
   360  	acc, err := ks.NewAccount("")
   361  	assert.Nil(t, err)
   362  	mockSender := &MockPeerInvoiceSender{
   363  		chanToWriteTo: make(chan crypto.Invoice, 10),
   364  	}
   365  
   366  	exchangeMessageChan := make(chan crypto.ExchangeMessage)
   367  	bolt, err := boltdb.NewStorage(dir)
   368  	assert.Nil(t, err)
   369  	defer bolt.Close()
   370  
   371  	tracker := session.NewTracker(mbtime.Now)
   372  	invoiceStorage := NewProviderInvoiceStorage(NewInvoiceStorage(bolt))
   373  	deps := InvoiceTrackerDeps{
   374  		AgreedPrice:                *market.NewPrice(60000000000000, 0),
   375  		Peer:                       identity.FromAddress("some peer"),
   376  		PeerInvoiceSender:          mockSender,
   377  		InvoiceStorage:             invoiceStorage,
   378  		TimeTracker:                &tracker,
   379  		LimitChargePeriod:          time.Nanosecond,
   380  		LimitNotPaidInvoice:        big.NewInt(0),
   381  		ChargePeriod:               time.Nanosecond,
   382  		ChargePeriodLeeway:         15 * time.Minute,
   383  		ExchangeMessageChan:        exchangeMessageChan,
   384  		ExchangeMessageWaitTimeout: time.Second,
   385  		ProviderID:                 identity.FromAddress(acc.Address.Hex()),
   386  		ConsumersHermesID:          acc.Address,
   387  		AddressProvider:            &mockAddressProvider{},
   388  		HermesStatusChecker:        &mockHermesStatusChecker{statusToReturn: HermesStatus{IsActive: true}},
   389  		EventBus:                   mocks.NewEventBus(),
   390  	}
   391  	invoiceTracker := NewInvoiceTracker(deps)
   392  	defer invoiceTracker.Stop()
   393  
   394  	errChan := make(chan error)
   395  	go func() { errChan <- invoiceTracker.Start() }()
   396  
   397  	invoice := <-mockSender.chanToWriteTo
   398  	assert.Equal(t, providerFirstInvoiceValue, invoice.AgreementTotal)
   399  	assert.Len(t, invoice.Hashlock, 64)
   400  	assert.Equal(t, strings.ToLower(acc.Address.Hex()), strings.ToLower(invoice.Provider))
   401  
   402  	invoiceTracker.Stop()
   403  	assert.NoError(t, <-errChan)
   404  }
   405  
   406  func Test_InvoiceTracker_FreeServiceSendsInvoices(t *testing.T) {
   407  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
   408  	assert.Nil(t, err)
   409  	defer os.RemoveAll(dir)
   410  
   411  	ks := identity.NewMockKeystore()
   412  	acc, err := ks.NewAccount("")
   413  	assert.Nil(t, err)
   414  	mockSender := &MockPeerInvoiceSender{
   415  		chanToWriteTo: make(chan crypto.Invoice, 10),
   416  	}
   417  
   418  	exchangeMessageChan := make(chan crypto.ExchangeMessage)
   419  	bolt, err := boltdb.NewStorage(dir)
   420  	assert.Nil(t, err)
   421  	defer bolt.Close()
   422  
   423  	tracker := session.NewTracker(mbtime.Now)
   424  	invoiceStorage := NewProviderInvoiceStorage(NewInvoiceStorage(bolt))
   425  	deps := InvoiceTrackerDeps{
   426  		AgreedPrice:                *market.NewPrice(600, 0),
   427  		Peer:                       identity.FromAddress("some peer"),
   428  		PeerInvoiceSender:          mockSender,
   429  		InvoiceStorage:             invoiceStorage,
   430  		TimeTracker:                &tracker,
   431  		LimitChargePeriod:          time.Nanosecond,
   432  		LimitNotPaidInvoice:        big.NewInt(0),
   433  		ChargePeriod:               time.Nanosecond,
   434  		ChargePeriodLeeway:         15 * time.Second,
   435  		ExchangeMessageChan:        exchangeMessageChan,
   436  		ExchangeMessageWaitTimeout: time.Second,
   437  		ProviderID:                 identity.FromAddress(acc.Address.Hex()),
   438  		ConsumersHermesID:          acc.Address,
   439  		AddressProvider:            &mockAddressProvider{},
   440  		HermesStatusChecker:        &mockHermesStatusChecker{statusToReturn: HermesStatus{IsActive: true}},
   441  		EventBus:                   mocks.NewEventBus(),
   442  	}
   443  	invoiceTracker := NewInvoiceTracker(deps)
   444  	defer invoiceTracker.Stop()
   445  
   446  	errChan := make(chan error)
   447  	go func() { errChan <- invoiceTracker.Start() }()
   448  
   449  	invoice := <-mockSender.chanToWriteTo
   450  	assert.Equal(t, big.NewInt(0), invoice.AgreementTotal)
   451  	assert.Len(t, invoice.Hashlock, 64)
   452  	assert.Equal(t, strings.ToLower(acc.Address.Hex()), strings.ToLower(invoice.Provider))
   453  
   454  	invoiceTracker.Stop()
   455  	assert.NoError(t, <-errChan)
   456  }
   457  
   458  func Test_sendsInvoiceIfThresholdReached(t *testing.T) {
   459  	tracker := session.NewTracker(mbtime.Now)
   460  	tracker.StartTracking()
   461  	deps := InvoiceTrackerDeps{
   462  		TimeTracker:       &tracker,
   463  		EventBus:          mocks.NewEventBus(),
   464  		AgreedPrice:       *market.NewPrice(600, 10995116277760),
   465  		MaxNotPaidInvoice: big.NewInt(100),
   466  	}
   467  	invoiceTracker := NewInvoiceTracker(deps)
   468  	invoiceTracker.dataTransferred = DataTransferred{
   469  		Up:   100,
   470  		Down: 100,
   471  	}
   472  	invoiceTracker.invoiceDebounceRate = time.Nanosecond
   473  	defer invoiceTracker.Stop()
   474  
   475  	go invoiceTracker.sendInvoicesWhenNeeded(time.Millisecond * 5)
   476  
   477  	res := <-invoiceTracker.invoiceChannel
   478  	assert.True(t, res)
   479  }
   480  
   481  func Test_sendsInvoiceIfTimePassed(t *testing.T) {
   482  	tracker := session.NewTracker(mbtime.Now)
   483  	tracker.StartTracking()
   484  	deps := InvoiceTrackerDeps{
   485  		TimeTracker:         &tracker,
   486  		EventBus:            mocks.NewEventBus(),
   487  		AgreedPrice:         *market.NewPrice(600, 0),
   488  		MaxNotPaidInvoice:   big.NewInt(100),
   489  		ChargePeriod:        time.Millisecond * 2,
   490  		LimitChargePeriod:   time.Millisecond * 3,
   491  		LimitNotPaidInvoice: big.NewInt(0),
   492  	}
   493  	invoiceTracker := NewInvoiceTracker(deps)
   494  	invoiceTracker.dataTransferred = DataTransferred{
   495  		Up:   1,
   496  		Down: 1,
   497  	}
   498  	invoiceTracker.invoiceDebounceRate = time.Nanosecond
   499  
   500  	wait := make(chan struct{}, 0)
   501  	go func() {
   502  		defer close(wait)
   503  		invoiceTracker.sendInvoicesWhenNeeded(time.Millisecond * 5)
   504  	}()
   505  
   506  	res := <-invoiceTracker.invoiceChannel
   507  	assert.False(t, res)
   508  	res = <-invoiceTracker.invoiceChannel
   509  	assert.False(t, res)
   510  	invoiceTracker.Stop()
   511  
   512  	<-wait
   513  	// Test that MaxUnpaid and ChargePeriod Increased
   514  	assert.Equal(t, time.Millisecond*3, invoiceTracker.deps.ChargePeriod, "charge period should increase up to limit")
   515  
   516  }
   517  
   518  func Test_sendsInvoiceIfDataUsed(t *testing.T) {
   519  	tracker := session.NewTracker(mbtime.Now)
   520  	tracker.StartTracking()
   521  	deps := InvoiceTrackerDeps{
   522  		TimeTracker:         &tracker,
   523  		EventBus:            mocks.NewEventBus(),
   524  		AgreedPrice:         *market.NewPrice(600, 100),
   525  		MaxNotPaidInvoice:   big.NewInt(100),
   526  		ChargePeriod:        time.Millisecond * 2,
   527  		LimitChargePeriod:   time.Millisecond * 3,
   528  		LimitNotPaidInvoice: big.NewInt(140),
   529  	}
   530  	invoiceTracker := NewInvoiceTracker(deps)
   531  	invoiceTracker.invoiceDebounceRate = time.Nanosecond
   532  	invoiceTracker.dataTransferred = DataTransferred{
   533  		Up:   1000000000,
   534  		Down: 1000000000,
   535  	}
   536  	invoiceTracker.invoiceDebounceRate = time.Millisecond * 1
   537  
   538  	wait := make(chan struct{}, 0)
   539  	go func() {
   540  		defer close(wait)
   541  		invoiceTracker.sendInvoicesWhenNeeded(time.Millisecond * 5)
   542  	}()
   543  
   544  	res := <-invoiceTracker.invoiceChannel
   545  	assert.True(t, res)
   546  	res = <-invoiceTracker.invoiceChannel
   547  	assert.True(t, res)
   548  	invoiceTracker.Stop()
   549  
   550  	<-wait
   551  	// Test that MaxUnpaid and ChargePeriod Increased
   552  	assert.Equal(t, big.NewInt(140), invoiceTracker.deps.MaxNotPaidInvoice, "max unpaid invoice should increase up to limit")
   553  
   554  }
   555  
   556  func Test_calculateMaxNotReceivedExchangeMessageCount(t *testing.T) {
   557  	res := calculateMaxNotReceivedExchangeMessageCount(time.Minute*5, time.Second*240)
   558  	assert.Equal(t, uint64(1), res)
   559  	res = calculateMaxNotReceivedExchangeMessageCount(time.Minute*5, time.Second*20)
   560  	assert.Equal(t, uint64(15), res)
   561  	res = calculateMaxNotReceivedExchangeMessageCount(time.Hour*2, time.Second*20)
   562  	assert.Equal(t, uint64(360), res)
   563  }
   564  
   565  func generateExchangeMessage(t *testing.T, amount *big.Int, invoice crypto.Invoice, channel string) (crypto.ExchangeMessage, string) {
   566  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
   567  	assert.Nil(t, err)
   568  	defer os.RemoveAll(dir)
   569  
   570  	ks := identity.NewMockKeystore()
   571  	acc, err := ks.NewAccount("")
   572  	assert.Nil(t, err)
   573  
   574  	err = ks.Unlock(acc, "")
   575  	assert.Nil(t, err)
   576  
   577  	if channel == "" {
   578  		addr, err := crypto.GenerateChannelAddress(acc.Address.Hex(), mockHermesAddress, mockRegistryAddress, mockChannelImplementation)
   579  		assert.Nil(t, err)
   580  		channel = addr
   581  	}
   582  
   583  	em, err := crypto.CreateExchangeMessage(1, invoice, amount, channel, "", ks, acc.Address)
   584  	assert.Nil(t, err)
   585  	if em != nil {
   586  		return *em, acc.Address.Hex()
   587  	}
   588  	return crypto.ExchangeMessage{}, acc.Address.Hex()
   589  }
   590  
   591  func TestInvoiceTracker_receiveExchangeMessageOrTimeout(t *testing.T) {
   592  	dir, err := os.MkdirTemp("", "invoice_tracker_test")
   593  	assert.Nil(t, err)
   594  	defer os.RemoveAll(dir)
   595  
   596  	bolt, err := boltdb.NewStorage(dir)
   597  	assert.Nil(t, err)
   598  	defer bolt.Close()
   599  
   600  	msg1, addr1 := generateExchangeMessage(t, big.NewInt(10), crypto.Invoice{AgreementTotal: big.NewInt(10), AgreementID: new(big.Int), TransactorFee: new(big.Int)}, "0x441Da57A51e42DAB7Daf55909Af93A9b00eEF23C")
   601  	msg2, addr2 := generateExchangeMessage(t, big.NewInt(10), crypto.Invoice{AgreementTotal: big.NewInt(10), AgreementID: new(big.Int), TransactorFee: new(big.Int), Hashlock: "0x441Da57A51e42DAB7Daf55909Af93A9b00eEF23C"}, "0x441Da57A51e42DAB7Daf55909Af93A9b00eEF23C")
   602  	msg3, addr3 := generateExchangeMessage(t, big.NewInt(10), crypto.Invoice{AgreementTotal: big.NewInt(10), AgreementID: new(big.Int), TransactorFee: new(big.Int), Hashlock: "0x441Da57A51e42DAB7Daf55909Af93A9b00eEF23C"}, "")
   603  	type fields struct {
   604  		peer                       identity.Identity
   605  		exchangeMessageChan        chan crypto.ExchangeMessage
   606  		exchangeMessageWaitTimeout time.Duration
   607  		hermesFailureCount         uint64
   608  		hermesPromiseStorage       hermesPromiseStorage
   609  		hermesID                   common.Address
   610  		AgreementID                *big.Int
   611  		lastExchangeMessage        crypto.ExchangeMessage
   612  		invoicesSent               map[string]sentInvoice
   613  		addressProvider            addressProvider
   614  	}
   615  	tests := []struct {
   616  		name    string
   617  		fields  fields
   618  		wantErr bool
   619  		em      *crypto.ExchangeMessage
   620  	}{
   621  		{
   622  			name:    "errors on invalid signature",
   623  			wantErr: true,
   624  			fields: fields{
   625  				exchangeMessageWaitTimeout: time.Minute,
   626  				exchangeMessageChan:        make(chan crypto.ExchangeMessage),
   627  				peer:                       identity.FromAddress(addr1),
   628  				lastExchangeMessage: crypto.ExchangeMessage{
   629  					Promise: crypto.Promise{
   630  						Amount: new(big.Int),
   631  						Fee:    new(big.Int),
   632  					},
   633  					AgreementID:    new(big.Int),
   634  					AgreementTotal: new(big.Int),
   635  				},
   636  			},
   637  			em: &crypto.ExchangeMessage{},
   638  		},
   639  		{
   640  			name:    "errors on missmatching hashlocks",
   641  			wantErr: true,
   642  			fields: fields{
   643  				exchangeMessageWaitTimeout: time.Minute,
   644  				exchangeMessageChan:        make(chan crypto.ExchangeMessage),
   645  				peer:                       identity.FromAddress(addr1),
   646  				lastExchangeMessage: crypto.ExchangeMessage{
   647  					Promise: crypto.Promise{
   648  						Amount: new(big.Int),
   649  						Fee:    new(big.Int),
   650  					},
   651  					AgreementID:    new(big.Int),
   652  					AgreementTotal: new(big.Int),
   653  				},
   654  			},
   655  			em: &msg1,
   656  		},
   657  		{
   658  			name:    "errors on bad channel ID",
   659  			wantErr: true,
   660  			fields: fields{
   661  				exchangeMessageWaitTimeout: time.Minute,
   662  				exchangeMessageChan:        make(chan crypto.ExchangeMessage),
   663  				peer:                       identity.FromAddress(addr2),
   664  				lastExchangeMessage: crypto.ExchangeMessage{
   665  					Promise: crypto.Promise{
   666  						Amount: new(big.Int),
   667  						Fee:    new(big.Int),
   668  					},
   669  					AgreementID:    new(big.Int),
   670  					AgreementTotal: new(big.Int),
   671  				},
   672  			},
   673  			em: &msg2,
   674  		},
   675  		{
   676  			name:    "completes green path",
   677  			wantErr: false,
   678  			fields: fields{
   679  				addressProvider:            &mockAddressProvider{addrToReturn: common.BytesToAddress(msg3.Promise.ChannelID)},
   680  				exchangeMessageWaitTimeout: time.Minute,
   681  				exchangeMessageChan:        make(chan crypto.ExchangeMessage),
   682  				hermesPromiseStorage:       &mockHermesPromiseStorage{},
   683  				peer:                       identity.FromAddress(addr3),
   684  				hermesID:                   common.HexToAddress(mockHermesAddress),
   685  				lastExchangeMessage: crypto.ExchangeMessage{
   686  					Promise: crypto.Promise{
   687  						Amount: new(big.Int),
   688  						Fee:    new(big.Int),
   689  					},
   690  					AgreementID:    new(big.Int),
   691  					AgreementTotal: new(big.Int),
   692  				},
   693  				invoicesSent: map[string]sentInvoice{
   694  					hex.EncodeToString(msg3.Promise.Hashlock): {
   695  						invoice: crypto.Invoice{
   696  							Hashlock: hex.EncodeToString(msg3.Promise.Hashlock),
   697  						},
   698  					},
   699  				},
   700  			},
   701  			em: &msg3,
   702  		},
   703  	}
   704  	for _, tt := range tests {
   705  		t.Run(tt.name, func(t *testing.T) {
   706  			deps := InvoiceTrackerDeps{
   707  				Peer:                       tt.fields.peer,
   708  				ExchangeMessageChan:        tt.fields.exchangeMessageChan,
   709  				ExchangeMessageWaitTimeout: tt.fields.exchangeMessageWaitTimeout,
   710  				ConsumersHermesID:          tt.fields.hermesID,
   711  				EventBus:                   mocks.NewEventBus(),
   712  				InvoiceStorage:             NewProviderInvoiceStorage(NewInvoiceStorage(bolt)),
   713  				AddressProvider:            tt.fields.addressProvider,
   714  				AgreedPrice:                *market.NewPrice(0, 0),
   715  				LimitChargePeriod:          time.Nanosecond,
   716  				LimitNotPaidInvoice:        big.NewInt(0),
   717  			}
   718  			it := &InvoiceTracker{
   719  				hermesFailureCount:  tt.fields.hermesFailureCount,
   720  				lastExchangeMessage: tt.fields.lastExchangeMessage,
   721  				agreementID:         tt.fields.AgreementID,
   722  				deps:                deps,
   723  				invoicesSent:        tt.fields.invoicesSent,
   724  			}
   725  			if err := it.handleExchangeMessage(*tt.em); (err != nil) != tt.wantErr {
   726  				t.Errorf("InvoiceTracker.receiveExchangeMessageOrTimeout() error = %v, wantErr %v", err, tt.wantErr)
   727  			}
   728  		})
   729  	}
   730  }
   731  
   732  func TestInvoiceTracker_handleHermesError(t *testing.T) {
   733  	tests := []struct {
   734  		name                  string
   735  		maxHermesFailureCount uint64
   736  		err                   error
   737  		wantErr               error
   738  	}{
   739  		{
   740  			name:    "ignores nil errors",
   741  			wantErr: nil,
   742  			err:     nil,
   743  		},
   744  		{
   745  			name:    "handles wrapped errors",
   746  			wantErr: ErrHermesInternal,
   747  			err:     errors.Wrap(ErrHermesInternal, "pita bread"),
   748  		},
   749  		{
   750  			name:    "bubbles internal on failure exceeded",
   751  			wantErr: ErrHermesInternal,
   752  			err:     ErrHermesInternal,
   753  		},
   754  		{
   755  			name:                  "returns nil on internal not exceeding limit",
   756  			wantErr:               nil,
   757  			maxHermesFailureCount: 1,
   758  			err:                   ErrHermesInternal,
   759  		},
   760  		{
   761  			name:    "bubbles hashlock missmatch on failure exceeded",
   762  			wantErr: ErrHermesHashlockMissmatch,
   763  			err:     ErrHermesHashlockMissmatch,
   764  		},
   765  		{
   766  			name:                  "returns nil on hashlock missmatch not exceeding limit",
   767  			wantErr:               nil,
   768  			maxHermesFailureCount: 1,
   769  			err:                   ErrHermesHashlockMissmatch,
   770  		},
   771  		{
   772  			name:    "returns unknown error if failures exceeded",
   773  			wantErr: errors.New("unknown error"),
   774  			err:     errors.New("unknown error"),
   775  		},
   776  		{
   777  			name:                  "returns nil on unknown error if failures not exceeded",
   778  			wantErr:               nil,
   779  			maxHermesFailureCount: 100,
   780  			err:                   errors.New("unknown error"),
   781  		},
   782  		{
   783  			name:                  "returns overspend",
   784  			maxHermesFailureCount: 100,
   785  			wantErr:               ErrHermesOverspend,
   786  			err:                   ErrHermesOverspend,
   787  		},
   788  	}
   789  	for _, tt := range tests {
   790  		t.Run(tt.name, func(t *testing.T) {
   791  			it := &InvoiceTracker{
   792  				deps: InvoiceTrackerDeps{
   793  					MaxHermesFailureCount: tt.maxHermesFailureCount,
   794  					LimitChargePeriod:     time.Nanosecond,
   795  					LimitNotPaidInvoice:   big.NewInt(0),
   796  				},
   797  			}
   798  			err := it.handleHermesError(tt.err)
   799  			if tt.wantErr == nil {
   800  				assert.NoError(t, err, tt.name)
   801  			} else {
   802  				assert.EqualError(t, errors.Cause(err), tt.wantErr.Error(), tt.name)
   803  			}
   804  		})
   805  	}
   806  }
   807  
   808  type mockEncryptor struct {
   809  	errToReturn error
   810  }
   811  
   812  func (me *mockEncryptor) Decrypt(addr common.Address, encrypted []byte) ([]byte, error) {
   813  	return encrypted, me.errToReturn
   814  }
   815  
   816  func (me *mockEncryptor) Encrypt(addr common.Address, plaintext []byte) ([]byte, error) {
   817  	return plaintext, me.errToReturn
   818  }
   819  
   820  type mockHermesPromiseStorage struct {
   821  	toReturn    HermesPromise
   822  	errToReturn error
   823  }
   824  
   825  func (maps *mockHermesPromiseStorage) Store(_ HermesPromise) error {
   826  	return maps.errToReturn
   827  }
   828  
   829  func (maps *mockHermesPromiseStorage) Delete(_ HermesPromise) error {
   830  	return maps.errToReturn
   831  }
   832  
   833  func (maps *mockHermesPromiseStorage) Get(chainID int64, _ string) (HermesPromise, error) {
   834  	return maps.toReturn, maps.errToReturn
   835  }
   836  
   837  func (maps *mockHermesPromiseStorage) List(_ HermesPromiseFilter) ([]HermesPromise, error) {
   838  	return []HermesPromise{maps.toReturn}, maps.errToReturn
   839  }
   840  
   841  type testEvent struct {
   842  	name  string
   843  	value interface{}
   844  }
   845  
   846  type mockPublisher struct {
   847  	publicationChan chan testEvent
   848  }
   849  
   850  func (mp *mockPublisher) Publish(topic string, payload interface{}) {
   851  	if mp.publicationChan != nil {
   852  		mp.publicationChan <- testEvent{
   853  			name:  topic,
   854  			value: payload,
   855  		}
   856  	}
   857  }
   858  
   859  func (mp *mockPublisher) Subscribe(topic string, fn interface{}) error {
   860  	return nil
   861  }
   862  
   863  func (mp *mockPublisher) SubscribeWithUID(topic, uid string, fn interface{}) error {
   864  	return nil
   865  }
   866  
   867  func (mp *mockPublisher) SubscribeAsync(topic string, fn interface{}) error {
   868  	return nil
   869  }
   870  
   871  func (mp *mockPublisher) Unsubscribe(topic string, fn interface{}) error {
   872  	return nil
   873  }
   874  
   875  func (mp *mockPublisher) UnsubscribeWithUID(topic, uid string, fn interface{}) error {
   876  	return nil
   877  }
   878  
   879  type mockObserver struct {
   880  }
   881  
   882  func (mo *mockObserver) GetHermeses(f *observer.HermesFilter) (observer.HermesesResponse, error) {
   883  	return observer.HermesesResponse{}, nil
   884  }
   885  
   886  func (mo *mockObserver) GetHermesData(chainId int64, hermesAddress common.Address) (*observer.HermesResponse, error) {
   887  	return nil, nil
   888  }
   889  
   890  func TestInvoiceTracker_validateExchangeMessage(t *testing.T) {
   891  	type fields struct {
   892  		deps InvoiceTrackerDeps
   893  	}
   894  	type args struct {
   895  		em crypto.ExchangeMessage
   896  	}
   897  	tests := []struct {
   898  		name    string
   899  		fields  fields
   900  		args    args
   901  		wantErr bool
   902  	}{
   903  		{
   904  			args: args{
   905  				em: crypto.ExchangeMessage{
   906  					HermesID: "0x1",
   907  				},
   908  			},
   909  			name:    "rejects exchange message with unsupported hermes",
   910  			wantErr: true,
   911  			fields: fields{
   912  				deps: InvoiceTrackerDeps{},
   913  			},
   914  		},
   915  	}
   916  	for _, tt := range tests {
   917  		t.Run(tt.name, func(t *testing.T) {
   918  			it := &InvoiceTracker{
   919  				deps: tt.fields.deps,
   920  			}
   921  			if err := it.validateExchangeMessage(tt.args.em); (err != nil) != tt.wantErr {
   922  				t.Errorf("InvoiceTracker.validateExchangeMessage() error = %v, wantErr %v", err, tt.wantErr)
   923  			}
   924  		})
   925  	}
   926  }
   927  
   928  type mockHermesStatusChecker struct {
   929  	statusToReturn HermesStatus
   930  	errToReturn    error
   931  }
   932  
   933  func (mhsc *mockHermesStatusChecker) GetHermesStatus(chainID int64, registryAddress common.Address, hermesID common.Address) (HermesStatus, error) {
   934  	return mhsc.statusToReturn, mhsc.errToReturn
   935  }