github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/state/state_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 state 19 20 import ( 21 "math/big" 22 "reflect" 23 "sync" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/stretchr/testify/assert" 29 30 "github.com/mysteriumnetwork/node/consumer/session" 31 "github.com/mysteriumnetwork/node/core/connection/connectionstate" 32 "github.com/mysteriumnetwork/node/core/discovery/proposal" 33 "github.com/mysteriumnetwork/node/core/service" 34 "github.com/mysteriumnetwork/node/core/service/servicestate" 35 "github.com/mysteriumnetwork/node/datasize" 36 "github.com/mysteriumnetwork/node/eventbus" 37 "github.com/mysteriumnetwork/node/identity" 38 "github.com/mysteriumnetwork/node/identity/registry" 39 "github.com/mysteriumnetwork/node/market" 40 "github.com/mysteriumnetwork/node/mocks" 41 nodeSession "github.com/mysteriumnetwork/node/session" 42 sessionEvent "github.com/mysteriumnetwork/node/session/event" 43 "github.com/mysteriumnetwork/node/session/pingpong" 44 pingpongEvent "github.com/mysteriumnetwork/node/session/pingpong/event" 45 "github.com/mysteriumnetwork/node/tequilapi/contract" 46 "github.com/mysteriumnetwork/payments/crypto" 47 ) 48 49 type debounceTester struct { 50 numInteractions int 51 lock sync.Mutex 52 } 53 54 type interactionCounter interface { 55 interactions() int 56 } 57 58 func (dt *debounceTester) do(interface{}) { 59 dt.lock.Lock() 60 dt.numInteractions++ 61 dt.lock.Unlock() 62 } 63 64 func (dt *debounceTester) interactions() int { 65 dt.lock.Lock() 66 defer dt.lock.Unlock() 67 return dt.numInteractions 68 } 69 70 func Test_Debounce_CallsOnceInInterval(t *testing.T) { 71 dt := &debounceTester{} 72 duration := time.Millisecond * 10 73 f := debounce(dt.do, duration) 74 for i := 1; i < 10; i++ { 75 f(struct{}{}) 76 } 77 assert.Eventually(t, interacted(dt, 1), 2*time.Second, 10*time.Millisecond) 78 } 79 80 type mockPublisher struct { 81 lock sync.Mutex 82 publishedTopic string 83 publishedData interface{} 84 } 85 86 func (mp *mockPublisher) Publish(topic string, data interface{}) { 87 mp.lock.Lock() 88 defer mp.lock.Unlock() 89 mp.publishedData = data 90 mp.publishedTopic = topic 91 } 92 93 type serviceListerMock struct { 94 lock sync.Mutex 95 numInteractions int 96 servicesToReturn map[service.ID]*service.Instance 97 } 98 99 func (slm *serviceListerMock) interactions() int { 100 slm.lock.Lock() 101 defer slm.lock.Unlock() 102 return slm.numInteractions 103 } 104 105 func (slm *serviceListerMock) List(includeAll bool) []*service.Instance { 106 slm.lock.Lock() 107 defer slm.lock.Unlock() 108 slm.numInteractions++ 109 list := make([]*service.Instance, 0, len(slm.servicesToReturn)) 110 for _, instance := range slm.servicesToReturn { 111 list = append(list, instance) 112 } 113 return list 114 } 115 116 func Test_ConsumesSessionEvents(t *testing.T) { 117 // given 118 expected := sessionEvent.SessionContext{ 119 ID: "1", 120 StartedAt: time.Now(), 121 ConsumerID: identity.FromAddress("0x0000000000000000000000000000000000000001"), 122 HermesID: common.HexToAddress("0x000000000000000000000000000000000000000a"), 123 Proposal: market.ServiceProposal{ 124 Location: stubLocation, 125 }, 126 } 127 128 eventBus := eventbus.New() 129 deps := KeeperDeps{ 130 Publisher: eventBus, 131 IdentityProvider: &mocks.IdentityProvider{}, 132 EarningsProvider: &mockEarningsProvider{}, 133 } 134 keeper := NewKeeper(deps, time.Millisecond) 135 keeper.Subscribe(eventBus) 136 137 // when 138 eventBus.Publish(sessionEvent.AppTopicSession, sessionEvent.AppEventSession{ 139 Status: sessionEvent.CreatedStatus, 140 Session: expected, 141 }) 142 143 // then 144 assert.Eventually(t, func() bool { 145 return len(keeper.GetState().Sessions) == 1 146 }, 2*time.Second, 10*time.Millisecond) 147 assert.Equal( 148 t, 149 []session.History{ 150 { 151 SessionID: nodeSession.ID(expected.ID), 152 Direction: session.DirectionProvided, 153 ConsumerID: expected.ConsumerID, 154 HermesID: expected.HermesID.Hex(), 155 ProviderCountry: "MU", 156 Started: expected.StartedAt, 157 Status: session.StatusNew, 158 Tokens: new(big.Int), 159 }, 160 }, 161 keeper.GetState().Sessions, 162 ) 163 164 // when 165 eventBus.Publish(sessionEvent.AppTopicSession, sessionEvent.AppEventSession{ 166 Status: sessionEvent.RemovedStatus, 167 Session: expected, 168 }) 169 170 // then 171 assert.Eventually(t, func() bool { 172 return len(keeper.GetState().Sessions) == 0 173 }, 2*time.Second, 10*time.Millisecond) 174 } 175 176 func Test_ConsumesSessionAcknowledgeEvents(t *testing.T) { 177 // given 178 myID := "test" 179 expected := session.History{ 180 SessionID: nodeSession.ID("1"), 181 } 182 183 eventBus := eventbus.New() 184 deps := KeeperDeps{ 185 Publisher: eventBus, 186 IdentityProvider: &mocks.IdentityProvider{}, 187 EarningsProvider: &mockEarningsProvider{}, 188 } 189 keeper := NewKeeper(deps, time.Millisecond) 190 keeper.Subscribe(eventBus) 191 keeper.state.Services = []contract.ServiceInfoDTO{ 192 {ID: myID, ConnectionStatistics: &contract.ServiceStatisticsDTO{}}, 193 } 194 keeper.state.Sessions = []session.History{ 195 expected, 196 } 197 198 // when 199 eventBus.Publish(sessionEvent.AppTopicSession, sessionEvent.AppEventSession{ 200 Status: sessionEvent.AcknowledgedStatus, 201 Service: sessionEvent.ServiceContext{ 202 ID: myID, 203 }, 204 Session: sessionEvent.SessionContext{ 205 ID: string(expected.SessionID), 206 }, 207 }) 208 209 // then 210 assert.Eventually(t, func() bool { 211 return keeper.GetState().Services[0].ConnectionStatistics.Successful == 1 212 }, 2*time.Second, 10*time.Millisecond) 213 } 214 215 func Test_consumeServiceSessionEarningsEvent(t *testing.T) { 216 // given 217 eventBus := eventbus.New() 218 deps := KeeperDeps{ 219 Publisher: eventBus, 220 IdentityProvider: &mocks.IdentityProvider{}, 221 EarningsProvider: &mockEarningsProvider{}, 222 } 223 keeper := NewKeeper(deps, time.Millisecond) 224 keeper.Subscribe(eventBus) 225 keeper.state.Sessions = []session.History{ 226 {SessionID: nodeSession.ID("1")}, 227 } 228 229 // when 230 eventBus.Publish(sessionEvent.AppTopicTokensEarned, sessionEvent.AppEventTokensEarned{ 231 SessionID: "1", 232 Total: big.NewInt(500), 233 }) 234 235 // then 236 assert.Eventually(t, func() bool { 237 return keeper.GetState().Sessions[0].Tokens.Cmp(big.NewInt(0)) != 0 238 }, 2*time.Second, 10*time.Millisecond) 239 assert.Equal( 240 t, 241 []session.History{ 242 {SessionID: nodeSession.ID("1"), Tokens: big.NewInt(500)}, 243 }, 244 keeper.GetState().Sessions, 245 ) 246 } 247 248 func Test_consumeServiceSessionStatisticsEvent(t *testing.T) { 249 // given 250 eventBus := eventbus.New() 251 deps := KeeperDeps{ 252 Publisher: eventBus, 253 IdentityProvider: &mocks.IdentityProvider{}, 254 EarningsProvider: &mockEarningsProvider{}, 255 } 256 keeper := NewKeeper(deps, time.Millisecond) 257 keeper.Subscribe(eventBus) 258 keeper.state.Sessions = []session.History{ 259 {SessionID: nodeSession.ID("1")}, 260 } 261 262 // when 263 eventBus.Publish(sessionEvent.AppTopicDataTransferred, sessionEvent.AppEventDataTransferred{ 264 ID: "1", 265 Up: 1, 266 Down: 2, 267 }) 268 269 // then 270 assert.Eventually(t, func() bool { 271 return keeper.GetState().Sessions[0].DataReceived != 0 272 }, 2*time.Second, 10*time.Millisecond) 273 assert.Equal( 274 t, 275 []session.History{ 276 {SessionID: "1", DataSent: 2, DataReceived: 1}, 277 }, 278 keeper.GetState().Sessions, 279 ) 280 } 281 282 func Test_ConsumesServiceEvents(t *testing.T) { 283 mpr := mockProposalRepository{ 284 priceToAdd: market.Price{ 285 PricePerHour: big.NewInt(1), 286 PricePerGiB: big.NewInt(2), 287 }, 288 } 289 290 expected := service.Instance{ 291 Proposal: market.NewProposal("0xbeef", "wireguard", market.NewProposalOpts{}), 292 } 293 var id service.ID 294 295 publisher := &mockPublisher{} 296 sl := &serviceListerMock{ 297 servicesToReturn: map[service.ID]*service.Instance{ 298 id: &expected, 299 }, 300 } 301 302 duration := time.Millisecond * 3 303 deps := KeeperDeps{ 304 Publisher: publisher, 305 ServiceLister: sl, 306 IdentityProvider: &mocks.IdentityProvider{}, 307 EarningsProvider: &mockEarningsProvider{}, 308 ProposalPricer: &mpr, 309 } 310 keeper := NewKeeper(deps, duration) 311 312 for i := 0; i < 5; i++ { 313 // shoot a few events to see if we'll debounce 314 keeper.consumeServiceStateEvent(servicestate.AppEventServiceStatus{}) 315 } 316 317 assert.Eventually(t, interacted(sl, 1), 2*time.Second, 10*time.Millisecond) 318 319 actual := keeper.GetState().Services[0] 320 assert.Equal(t, string(id), actual.ID) 321 assert.Equal(t, expected.Type, actual.Type) 322 assert.Equal(t, expected.ProviderID.Address, actual.ProviderID) 323 assert.Equal(t, expected.Options, actual.Options) 324 assert.Equal(t, string(expected.State()), actual.Status) 325 expt, _ := mpr.EnrichProposalWithPrice(expected.Proposal) 326 assert.EqualValues(t, contract.NewProposalDTO(expt), *actual.Proposal) 327 } 328 329 func Test_ConsumesConnectionStateEvents(t *testing.T) { 330 // given 331 expected := connectionstate.Status{ 332 State: connectionstate.Connected, 333 SessionID: "1", 334 Proposal: proposal.PricedServiceProposal{ 335 ServiceProposal: market.ServiceProposal{ 336 Contacts: market.ContactList{}, 337 }, 338 }, 339 } 340 eventBus := eventbus.New() 341 deps := KeeperDeps{ 342 Publisher: eventBus, 343 ServiceLister: &serviceListerMock{}, 344 IdentityProvider: &mocks.IdentityProvider{}, 345 EarningsProvider: &mockEarningsProvider{}, 346 } 347 keeper := NewKeeper(deps, time.Millisecond) 348 err := keeper.Subscribe(eventBus) 349 assert.NoError(t, err) 350 assert.Equal(t, connectionstate.NotConnected, keeper.GetConnection("1").Session.State) 351 352 // when 353 eventBus.Publish(connectionstate.AppTopicConnectionState, connectionstate.AppEventConnectionState{ 354 State: expected.State, 355 SessionInfo: expected, 356 }) 357 358 // then 359 assert.Eventually(t, func() bool { 360 return keeper.GetConnection("1").Session.State == connectionstate.Connected 361 }, 2*time.Second, 10*time.Millisecond) 362 assert.Equal(t, expected, keeper.GetConnection("1").Session) 363 } 364 365 func Test_ConsumesConnectionStatisticsEvents(t *testing.T) { 366 // given 367 expected := connectionstate.Statistics{ 368 At: time.Now(), 369 BytesReceived: 10 * datasize.MiB.Bytes(), 370 BytesSent: 500 * datasize.KiB.Bytes(), 371 } 372 eventBus := eventbus.New() 373 deps := KeeperDeps{ 374 Publisher: eventBus, 375 ServiceLister: &serviceListerMock{}, 376 IdentityProvider: &mocks.IdentityProvider{}, 377 EarningsProvider: &mockEarningsProvider{}, 378 } 379 keeper := NewKeeper(deps, time.Millisecond) 380 err := keeper.Subscribe(eventBus) 381 assert.NoError(t, err) 382 assert.True(t, keeper.GetConnection("").Statistics.At.IsZero()) 383 384 // when 385 eventBus.Publish(connectionstate.AppTopicConnectionStatistics, connectionstate.AppEventConnectionStatistics{ 386 Stats: expected, 387 }) 388 389 // then 390 assert.Eventually(t, func() bool { 391 return expected == keeper.GetConnection("").Statistics 392 }, 2*time.Second, 10*time.Millisecond) 393 } 394 395 func Test_ConsumesConnectionInvoiceEvents(t *testing.T) { 396 // given 397 expected := crypto.Invoice{ 398 AgreementID: big.NewInt(1), 399 AgreementTotal: big.NewInt(1001), 400 TransactorFee: big.NewInt(10), 401 } 402 eventBus := eventbus.New() 403 deps := KeeperDeps{ 404 Publisher: eventBus, 405 ServiceLister: &serviceListerMock{}, 406 IdentityProvider: &mocks.IdentityProvider{}, 407 EarningsProvider: &mockEarningsProvider{}, 408 } 409 keeper := NewKeeper(deps, time.Millisecond) 410 err := keeper.Subscribe(eventBus) 411 assert.NoError(t, err) 412 assert.True(t, keeper.GetConnection("").Statistics.At.IsZero()) 413 414 // when 415 eventBus.Publish(pingpongEvent.AppTopicInvoicePaid, pingpongEvent.AppEventInvoicePaid{ 416 Invoice: expected, 417 }) 418 419 // then 420 assert.Eventually(t, func() bool { 421 return reflect.DeepEqual(expected, keeper.GetConnection("").Invoice) 422 }, 2*time.Second, 10*time.Millisecond) 423 } 424 425 func Test_ConsumesBalanceChangeEvent(t *testing.T) { 426 // given 427 eventBus := eventbus.New() 428 deps := KeeperDeps{ 429 Publisher: eventBus, 430 ServiceLister: &serviceListerMock{}, 431 IdentityProvider: &mocks.IdentityProvider{ 432 Identities: []identity.Identity{ 433 {Address: "0x000000000000000000000000000000000000000a"}, 434 }, 435 }, 436 IdentityRegistry: &mocks.IdentityRegistry{Status: registry.Registered}, 437 IdentityChannelCalculator: &mockChannelAddressCalculator{}, 438 BalanceProvider: &mockBalanceProvider{Balance: big.NewInt(0)}, 439 EarningsProvider: &mockEarningsProvider{}, 440 } 441 keeper := NewKeeper(deps, time.Millisecond) 442 err := keeper.Subscribe(eventBus) 443 assert.NoError(t, err) 444 assert.Zero(t, keeper.GetState().Identities[0].Balance.Uint64()) 445 446 // when 447 eventBus.Publish(pingpongEvent.AppTopicBalanceChanged, pingpongEvent.AppEventBalanceChanged{ 448 Identity: identity.Identity{Address: "0x000000000000000000000000000000000000000a"}, 449 Previous: big.NewInt(0), 450 Current: big.NewInt(999), 451 }) 452 453 // then 454 assert.Eventually(t, func() bool { 455 return keeper.GetState().Identities[0].Balance.Cmp(big.NewInt(999)) == 0 456 }, 2*time.Second, 10*time.Millisecond) 457 } 458 459 func Test_ConsumesEarningsChangeEvent(t *testing.T) { 460 // given 461 eventBus := eventbus.New() 462 channelsProvider := &mockEarningsProvider{ 463 Channels: []pingpong.HermesChannel{ 464 {ChannelID: "1"}, 465 }, 466 } 467 468 deps := KeeperDeps{ 469 Publisher: eventBus, 470 ServiceLister: &serviceListerMock{}, 471 IdentityProvider: &mocks.IdentityProvider{ 472 Identities: []identity.Identity{ 473 {Address: "0x000000000000000000000000000000000000000a"}, 474 }, 475 }, 476 IdentityRegistry: &mocks.IdentityRegistry{Status: registry.Registered}, 477 IdentityChannelCalculator: &mockChannelAddressCalculator{}, 478 BalanceProvider: &mockBalanceProvider{Balance: big.NewInt(0)}, 479 EarningsProvider: channelsProvider, 480 } 481 keeper := NewKeeper(deps, time.Millisecond) 482 err := keeper.Subscribe(eventBus) 483 assert.NoError(t, err) 484 assert.Zero(t, keeper.GetState().Identities[0].Balance.Uint64()) 485 assert.Len(t, keeper.GetState().ProviderChannels, 1) 486 assert.Equal(t, channelsProvider.Channels, keeper.GetState().ProviderChannels) 487 488 // when 489 channelsProvider.Channels = []pingpong.HermesChannel{ 490 {ChannelID: "1"}, 491 {ChannelID: "2"}, 492 } 493 eventBus.Publish(pingpongEvent.AppTopicEarningsChanged, pingpongEvent.AppEventEarningsChanged{ 494 Identity: identity.Identity{Address: "0x000000000000000000000000000000000000000a"}, 495 Previous: pingpongEvent.EarningsDetailed{}, 496 Current: pingpongEvent.EarningsDetailed{ 497 Total: pingpongEvent.Earnings{ 498 LifetimeBalance: big.NewInt(100), 499 UnsettledBalance: big.NewInt(10), 500 }, 501 }, 502 }) 503 504 // then 505 assert.Eventually(t, func() bool { 506 return keeper.GetState().Identities[0].Earnings.Cmp(big.NewInt(10)) == 0 && keeper.GetState().Identities[0].EarningsTotal.Cmp(big.NewInt(100)) == 0 507 }, 2*time.Second, 10*time.Millisecond) 508 assert.Len(t, keeper.GetState().ProviderChannels, 2) 509 assert.Equal(t, channelsProvider.Channels, keeper.GetState().ProviderChannels) 510 } 511 512 func Test_ConsumesIdentityRegistrationEvent(t *testing.T) { 513 // given 514 eventBus := eventbus.New() 515 deps := KeeperDeps{ 516 Publisher: eventBus, 517 ServiceLister: &serviceListerMock{}, 518 IdentityProvider: &mocks.IdentityProvider{ 519 Identities: []identity.Identity{ 520 {Address: "0x000000000000000000000000000000000000000a"}, 521 }, 522 }, 523 IdentityRegistry: &mocks.IdentityRegistry{Status: registry.Unregistered}, 524 IdentityChannelCalculator: &mockChannelAddressCalculator{}, 525 BalanceProvider: &mockBalanceProvider{Balance: big.NewInt(0)}, 526 EarningsProvider: &mockEarningsProvider{}, 527 } 528 keeper := NewKeeper(deps, time.Millisecond) 529 err := keeper.Subscribe(eventBus) 530 assert.NoError(t, err) 531 assert.Equal(t, registry.Unregistered, keeper.GetState().Identities[0].RegistrationStatus) 532 533 // when 534 eventBus.Publish(registry.AppTopicIdentityRegistration, registry.AppEventIdentityRegistration{ 535 ID: identity.Identity{Address: "0x000000000000000000000000000000000000000a"}, 536 Status: registry.Registered, 537 }) 538 539 // then 540 assert.Eventually(t, func() bool { 541 return keeper.GetState().Identities[0].RegistrationStatus == registry.Registered 542 }, 2*time.Second, 10*time.Millisecond) 543 } 544 545 func Test_getServiceByID(t *testing.T) { 546 publisher := &mockPublisher{} 547 sl := &serviceListerMock{ 548 servicesToReturn: map[service.ID]*service.Instance{}, 549 } 550 551 duration := time.Millisecond * 3 552 deps := KeeperDeps{ 553 Publisher: publisher, 554 ServiceLister: sl, 555 IdentityProvider: &mocks.IdentityProvider{}, 556 EarningsProvider: &mockEarningsProvider{}, 557 } 558 keeper := NewKeeper(deps, duration) 559 myID := "test" 560 keeper.state.Services = []contract.ServiceInfoDTO{ 561 {ID: myID}, 562 {ID: "mock"}, 563 } 564 565 s, found := keeper.getServiceByID(myID) 566 assert.True(t, found) 567 568 assert.EqualValues(t, keeper.state.Services[0], s) 569 570 _, found = keeper.getServiceByID("something else") 571 assert.False(t, found) 572 } 573 574 func Test_incrementConnectionCount(t *testing.T) { 575 expected := service.Instance{} 576 var id service.ID 577 578 publisher := &mockPublisher{} 579 sl := &serviceListerMock{ 580 servicesToReturn: map[service.ID]*service.Instance{ 581 id: &expected, 582 }, 583 } 584 585 duration := time.Millisecond * 3 586 deps := KeeperDeps{ 587 Publisher: publisher, 588 ServiceLister: sl, 589 IdentityProvider: &mocks.IdentityProvider{}, 590 EarningsProvider: &mockEarningsProvider{}, 591 } 592 keeper := NewKeeper(deps, duration) 593 myID := "test" 594 keeper.state.Services = []contract.ServiceInfoDTO{ 595 {ID: myID, ConnectionStatistics: &contract.ServiceStatisticsDTO{}}, 596 {ID: "mock", ConnectionStatistics: &contract.ServiceStatisticsDTO{}}, 597 } 598 599 keeper.incrementConnectCount(myID, false) 600 s, found := serviceByID(keeper.GetState().Services, myID) 601 assert.True(t, found) 602 603 assert.Equal(t, 1, s.ConnectionStatistics.Attempted) 604 assert.Equal(t, 0, s.ConnectionStatistics.Successful) 605 606 keeper.incrementConnectCount(myID, true) 607 s, found = serviceByID(keeper.GetState().Services, myID) 608 assert.True(t, found) 609 610 assert.Equal(t, 1, s.ConnectionStatistics.Successful) 611 assert.Equal(t, 1, s.ConnectionStatistics.Attempted) 612 } 613 614 func interacted(c interactionCounter, times int) func() bool { 615 return func() bool { 616 return c.interactions() == times 617 } 618 } 619 620 type mockBalanceProvider struct { 621 Balance *big.Int 622 } 623 624 // GetBalance returns a pre-defined balance. 625 func (mbp *mockBalanceProvider) GetBalance(_ int64, _ identity.Identity) *big.Int { 626 return mbp.Balance 627 } 628 629 type mockEarningsProvider struct { 630 Earnings pingpongEvent.EarningsDetailed 631 Channels []pingpong.HermesChannel 632 } 633 634 // List retrieves identity's channels with all known hermeses. 635 func (mep *mockEarningsProvider) List(chainID int64) []pingpong.HermesChannel { 636 return mep.Channels 637 } 638 639 // GetEarnings returns a pre-defined settlement state. 640 func (mep *mockEarningsProvider) GetEarningsDetailed(chainID int64, _ identity.Identity) *pingpongEvent.EarningsDetailed { 641 return &mep.Earnings 642 } 643 644 func serviceByID(services []contract.ServiceInfoDTO, id string) (se contract.ServiceInfoDTO, found bool) { 645 for i := range services { 646 if services[i].ID == id { 647 se = services[i] 648 found = true 649 return 650 } 651 } 652 return 653 } 654 655 var stubLocation = market.Location{Country: "MU"} 656 657 type mockChannelAddressCalculator struct{} 658 659 func (mcac *mockChannelAddressCalculator) GetActiveChannelAddress(chainID int64, id common.Address) (common.Address, error) { 660 return common.Address{}, nil 661 } 662 663 func (mcac *mockChannelAddressCalculator) GetActiveHermes(chainID int64) (common.Address, error) { 664 return common.Address{}, nil 665 } 666 667 type mockProposalRepository struct { 668 priceToAdd market.Price 669 } 670 671 func (m *mockProposalRepository) EnrichProposalWithPrice(in market.ServiceProposal) (proposal.PricedServiceProposal, error) { 672 return proposal.PricedServiceProposal{ 673 Price: m.priceToAdd, 674 ServiceProposal: in, 675 }, nil 676 }