github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/hermes_url_getter.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 18 package pingpong 19 20 import ( 21 "fmt" 22 "net/url" 23 "sync" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/mysteriumnetwork/payments/observer" 27 "github.com/rs/zerolog/log" 28 ) 29 30 // HermesURLGetter allows for fetching and storing of hermes urls. 31 type HermesURLGetter struct { 32 addressProvider addressProvider 33 bc bc 34 loadedAddresses map[int64]map[common.Address]string 35 loaddedAddressesLock sync.Mutex 36 observer observerApi 37 } 38 39 type addressProvider interface { 40 GetActiveChannelAddress(chainID int64, id common.Address) (common.Address, error) 41 GetArbitraryChannelAddress(hermes, registry, channel common.Address, id common.Address) (common.Address, error) 42 GetActiveChannelImplementation(chainID int64) (common.Address, error) 43 GetChannelImplementationForHermes(chainID int64, hermes common.Address) (common.Address, error) 44 GetMystAddress(chainID int64) (common.Address, error) 45 GetActiveHermes(chainID int64) (common.Address, error) 46 GetRegistryAddress(chainID int64) (common.Address, error) 47 GetKnownHermeses(chainID int64) ([]common.Address, error) 48 GetHermesChannelAddress(chainID int64, id, hermesAddr common.Address) (common.Address, error) 49 } 50 51 type observerApi interface { 52 GetHermeses(f *observer.HermesFilter) (observer.HermesesResponse, error) 53 GetHermesData(chainId int64, hermesAddress common.Address) (*observer.HermesResponse, error) 54 } 55 56 // NewHermesURLGetter creates a new instance of hermes url getter. 57 func NewHermesURLGetter( 58 bc bc, 59 addressProvider addressProvider, 60 observer observerApi, 61 ) *HermesURLGetter { 62 return &HermesURLGetter{ 63 loadedAddresses: make(map[int64]map[common.Address]string), 64 addressProvider: addressProvider, 65 bc: bc, 66 observer: observer, 67 } 68 } 69 70 type bc interface { 71 GetHermesURL(chainID int64, registryID, hermesID common.Address) (string, error) 72 } 73 74 const suffix = "api/v2" 75 76 func (hug *HermesURLGetter) normalizeAddress(address string) (string, error) { 77 u, err := url.ParseRequestURI(address) 78 if err != nil { 79 return "", fmt.Errorf("could not parse hermes URL: %w", err) 80 } 81 return fmt.Sprintf("%v://%v/%v", u.Scheme, u.Host, suffix), nil 82 } 83 84 // GetHermesURL fetches the hermes url from blockchain, observer or local cache if it has already been loaded. 85 func (hug *HermesURLGetter) GetHermesURL(chainID int64, address common.Address) (string, error) { 86 hug.loaddedAddressesLock.Lock() 87 defer hug.loaddedAddressesLock.Unlock() 88 89 addresses, ok := hug.loadedAddresses[chainID] 90 if ok { 91 v, ok := addresses[address] 92 if ok { 93 return v, nil 94 } 95 } else { 96 hug.loadedAddresses[chainID] = make(map[common.Address]string, 0) 97 } 98 99 url, err := hug.getHermesURLBC(chainID, address) 100 if err != nil { 101 log.Err(err).Fields(map[string]any{ 102 "chain_id": chainID, 103 "hermes_id": address.Hex(), 104 }).Msg("failed to get hermes url from blockchain, using fallback") 105 url, err = hug.getHermesURLObserver(chainID, address) 106 if err != nil { 107 return "", err 108 } 109 } 110 url, err = hug.normalizeAddress(url) 111 if err != nil { 112 return "", err 113 } 114 hug.loadedAddresses[chainID][address] = url 115 return url, nil 116 } 117 118 func (hug *HermesURLGetter) getHermesURLBC(chainID int64, address common.Address) (string, error) { 119 registry, err := hug.addressProvider.GetRegistryAddress(chainID) 120 if err != nil { 121 return "", err 122 } 123 return hug.bc.GetHermesURL(chainID, registry, address) 124 } 125 126 func (hug *HermesURLGetter) getHermesURLObserver(chainID int64, address common.Address) (string, error) { 127 hermesData, err := hug.observer.GetHermesData(chainID, address) 128 if err != nil { 129 return "", err 130 } 131 return hug.normalizeAddress(hermesData.URL) 132 }