github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/hermes_promise_handler_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  	"errors"
    22  	"testing"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/mysteriumnetwork/node/core/node/event"
    26  	"github.com/mysteriumnetwork/node/eventbus"
    27  	"github.com/mysteriumnetwork/node/identity"
    28  	"github.com/mysteriumnetwork/node/identity/registry"
    29  	"github.com/mysteriumnetwork/payments/crypto"
    30  	"github.com/rs/zerolog/log"
    31  	"github.com/stretchr/testify/assert"
    32  )
    33  
    34  func TestHermesPromiseHandler_RequestPromise(t *testing.T) {
    35  	bus := eventbus.New()
    36  	mockFactory := &mockHermesCallerFactory{}
    37  	aph := &HermesPromiseHandler{
    38  		deps: HermesPromiseHandlerDeps{
    39  			HermesURLGetter:      &mockHermesURLGetter{},
    40  			HermesCallerFactory:  mockFactory.Get,
    41  			Encryption:           &mockEncryptor{},
    42  			EventBus:             eventbus.New(),
    43  			HermesPromiseStorage: &mockHermesPromiseStorage{},
    44  			FeeProvider:          &mockFeeProvider{},
    45  		},
    46  		queue: make(chan enqueuedRequest),
    47  		stop:  make(chan struct{}),
    48  	}
    49  	aph.transactorFees = make(map[int64]registry.FeesResponse)
    50  	err := aph.Subscribe(bus)
    51  	assert.NoError(t, err)
    52  	bus.Publish(event.AppTopicNode, event.Payload{
    53  		Status: event.StatusStarted,
    54  	})
    55  
    56  	defer bus.Publish(event.AppTopicNode, event.Payload{
    57  		Status: event.StatusStopped,
    58  	})
    59  
    60  	r := []byte{0x0, 0x1}
    61  	em := crypto.ExchangeMessage{
    62  		Promise: crypto.Promise{},
    63  	}
    64  
    65  	ch := aph.RequestPromise(r, em, identity.FromAddress("0x0000000000000000000000000000000000000001"), "session")
    66  
    67  	err, more := <-ch
    68  	assert.False(t, more)
    69  	assert.Nil(t, err)
    70  }
    71  
    72  func TestHermesPromiseHandler_RequestPromise_BubblesErrors(t *testing.T) {
    73  	bus := eventbus.New()
    74  	mockFactory := &mockHermesCallerFactory{
    75  		errToReturn: ErrNeedsRRecovery,
    76  	}
    77  
    78  	aph := &HermesPromiseHandler{
    79  		deps: HermesPromiseHandlerDeps{
    80  			HermesURLGetter:     &mockHermesURLGetter{},
    81  			HermesCallerFactory: mockFactory.Get,
    82  			Encryption: &mockEncryptor{
    83  				errToReturn: errors.New("beep beep boop boop"),
    84  			},
    85  			EventBus:             bus,
    86  			HermesPromiseStorage: &mockHermesPromiseStorage{},
    87  			FeeProvider:          &mockFeeProvider{},
    88  		},
    89  		queue: make(chan enqueuedRequest),
    90  		stop:  make(chan struct{}),
    91  	}
    92  	aph.transactorFees = make(map[int64]registry.FeesResponse)
    93  	err := aph.Subscribe(bus)
    94  	assert.NoError(t, err)
    95  	bus.Publish(event.AppTopicNode, event.Payload{
    96  		Status: event.StatusStarted,
    97  	})
    98  
    99  	defer bus.Publish(event.AppTopicNode, event.Payload{
   100  		Status: event.StatusStopped,
   101  	})
   102  
   103  	r := []byte{0x0, 0x1}
   104  	em := crypto.ExchangeMessage{
   105  		Promise: crypto.Promise{},
   106  	}
   107  
   108  	ch := aph.RequestPromise(r, em, identity.FromAddress("0x0000000000000000000000000000000000000001"), "session")
   109  
   110  	err, more := <-ch
   111  	assert.True(t, more)
   112  	assert.Error(t, err)
   113  
   114  	err, more = <-ch
   115  	assert.False(t, more)
   116  	assert.Nil(t, err)
   117  }
   118  
   119  func TestHermesPromiseHandler_recoverR(t *testing.T) {
   120  	type fields struct {
   121  		deps       HermesPromiseHandlerDeps
   122  		providerID identity.Identity
   123  		chainID    int64
   124  		hermesID   common.Address
   125  	}
   126  	mockFactory := &mockHermesCallerFactory{}
   127  	tests := []struct {
   128  		name    string
   129  		fields  fields
   130  		err     hermesError
   131  		wantErr bool
   132  		before  func()
   133  	}{
   134  		{
   135  			name: "green path",
   136  			fields: fields{
   137  				deps: HermesPromiseHandlerDeps{
   138  					HermesCallerFactory: mockFactory.Get,
   139  					HermesURLGetter:     &mockHermesURLGetter{},
   140  					Encryption:          &mockEncryptor{},
   141  				},
   142  				providerID: identity.FromAddress("0x0"),
   143  			},
   144  			err: HermesErrorResponse{
   145  				ErrorMessage: `Secret R for previous promise exchange (Encrypted recovery data: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d"`,
   146  				CausedBy:     ErrNeedsRRecovery.Error(),
   147  				c:            ErrNeedsRRecovery,
   148  				ErrorData:    "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d",
   149  			},
   150  			wantErr: false,
   151  			before: func() {
   152  				mockFactory.errToReturn = nil
   153  			},
   154  		},
   155  		{
   156  			name: "bubbles hermes errors",
   157  			fields: fields{
   158  				providerID: identity.FromAddress("0x0"),
   159  				deps: HermesPromiseHandlerDeps{
   160  					HermesCallerFactory: mockFactory.Get,
   161  					HermesURLGetter:     &mockHermesURLGetter{},
   162  					Encryption:          &mockEncryptor{},
   163  				},
   164  			},
   165  			err: HermesErrorResponse{
   166  				ErrorMessage: `Secret R for previous promise exchange (Encrypted recovery data: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d"`,
   167  				CausedBy:     ErrNeedsRRecovery.Error(),
   168  				c:            ErrNeedsRRecovery,
   169  				ErrorData:    "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d",
   170  			},
   171  			wantErr: true,
   172  			before: func() {
   173  				mockFactory.errToReturn = errors.New("explosions")
   174  			},
   175  		},
   176  		{
   177  			name: "bubbles decryptor errors",
   178  			fields: fields{
   179  				providerID: identity.FromAddress("0x0"),
   180  				deps: HermesPromiseHandlerDeps{
   181  					HermesCallerFactory: mockFactory.Get,
   182  					HermesURLGetter:     &mockHermesURLGetter{},
   183  					Encryption: &mockEncryptor{
   184  						errToReturn: errors.New("explosions"),
   185  					},
   186  				},
   187  			},
   188  			err: HermesErrorResponse{
   189  				ErrorMessage: `Secret R for previous promise exchange (Encrypted recovery data: "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d"`,
   190  				CausedBy:     ErrNeedsRRecovery.Error(),
   191  				c:            ErrNeedsRRecovery,
   192  				ErrorData:    "7b2272223a223731373736353731373736353731373736353731333133343333333433333334363137333634363636313733363636343733363436363738363337363332373336363634376136633733363136623637363136653632363136333632366436653631363436363663366236613631373336343636363137333636222c2261677265656d656e745f6964223a3132333435367d",
   193  			},
   194  			wantErr: true,
   195  			before: func() {
   196  				mockFactory.errToReturn = nil
   197  			},
   198  		},
   199  	}
   200  	for _, tt := range tests {
   201  		if tt.before != nil {
   202  			tt.before()
   203  		}
   204  
   205  		t.Run(tt.name, func(t *testing.T) {
   206  			it := &HermesPromiseHandler{
   207  				deps: tt.fields.deps,
   208  			}
   209  			if err := it.recoverR(tt.err, tt.fields.providerID, tt.fields.chainID, tt.fields.hermesID); (err != nil) != tt.wantErr {
   210  				t.Errorf("HermesPromiseHandler.recoverR() error = %v, wantErr %v", err, tt.wantErr)
   211  			}
   212  		})
   213  	}
   214  }
   215  
   216  func TestHermesPromiseHandler_handleHermesError(t *testing.T) {
   217  	merr := errors.New("this is a test")
   218  	mockFactory := &mockHermesCallerFactory{}
   219  	tests := []struct {
   220  		name       string
   221  		err        error
   222  		wantErr    error
   223  		providerID identity.Identity
   224  		hermesID   common.Address
   225  		chainID    int64
   226  		deps       HermesPromiseHandlerDeps
   227  	}{
   228  		{
   229  			name:    "ignores nil errors",
   230  			wantErr: nil,
   231  			err:     nil,
   232  		},
   233  		{
   234  			name:    "returns nil on ErrHermesNoPreviousPromise",
   235  			wantErr: nil,
   236  			err:     ErrHermesNoPreviousPromise,
   237  		},
   238  		{
   239  			name:    "returns error if something else happens",
   240  			wantErr: ErrTooManyRequests,
   241  			err:     ErrTooManyRequests,
   242  		},
   243  		{
   244  			name: "bubbles R recovery errors",
   245  			deps: HermesPromiseHandlerDeps{
   246  				HermesCallerFactory: mockFactory.Get,
   247  				HermesURLGetter:     &mockHermesURLGetter{},
   248  				Encryption: &mockEncryptor{
   249  					errToReturn: merr,
   250  				},
   251  			},
   252  			providerID: identity.FromAddress("0x0"),
   253  			wantErr:    merr,
   254  			err: HermesErrorResponse{
   255  				c: ErrNeedsRRecovery,
   256  			},
   257  		},
   258  	}
   259  	for _, tt := range tests {
   260  		t.Run(tt.name, func(t *testing.T) {
   261  			aph := &HermesPromiseHandler{
   262  				deps: tt.deps,
   263  			}
   264  			err := aph.handleHermesError(tt.err, tt.providerID, tt.chainID, tt.hermesID)
   265  			if tt.wantErr == nil {
   266  				assert.NoError(t, err, tt.name)
   267  			} else {
   268  				log.Debug().Msgf("%v", err)
   269  				assert.True(t, errors.Is(err, tt.wantErr), tt.name)
   270  			}
   271  		})
   272  	}
   273  }
   274  
   275  type mockFeeProvider struct {
   276  	toReturn    registry.FeesResponse
   277  	errToReturn error
   278  }
   279  
   280  func (mfp *mockFeeProvider) FetchSettleFees(chainID int64) (registry.FeesResponse, error) {
   281  	return mfp.toReturn, mfp.errToReturn
   282  }
   283  
   284  type mockHermesCallerFactory struct {
   285  	errToReturn error
   286  }
   287  
   288  func (mhcf *mockHermesCallerFactory) Get(url string) HermesHTTPRequester {
   289  	return &mockHermesCaller{
   290  		errToReturn: mhcf.errToReturn,
   291  	}
   292  }
   293  
   294  type mockHermesURLGetter struct {
   295  	errToReturn error
   296  	urlToReturn string
   297  }
   298  
   299  func (mhug *mockHermesURLGetter) GetHermesURL(chainID int64, address common.Address) (string, error) {
   300  	return mhug.urlToReturn, mhug.errToReturn
   301  }