github.com/ledgerwatch/erigon-lib@v1.0.0/downloader/downloadercfg/downloadercfg.go (about) 1 /* 2 Copyright 2021 Erigon contributors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package downloadercfg 18 19 import ( 20 "io/ioutil" 21 "net" 22 "net/url" 23 "path/filepath" 24 "runtime" 25 "strings" 26 27 "github.com/anacrolix/dht/v2" 28 lg "github.com/anacrolix/log" 29 "github.com/anacrolix/torrent" 30 "github.com/c2h5oh/datasize" 31 "github.com/ledgerwatch/erigon-lib/common" 32 "github.com/ledgerwatch/erigon-lib/common/datadir" 33 "github.com/ledgerwatch/erigon-lib/common/dir" 34 "github.com/ledgerwatch/log/v3" 35 "golang.org/x/time/rate" 36 ) 37 38 // DefaultPieceSize - Erigon serves many big files, bigger pieces will reduce 39 // amount of network announcements, but can't go over 2Mb 40 // see https://wiki.theory.org/BitTorrentSpecification#Metainfo_File_Structure 41 const DefaultPieceSize = 2 * 1024 * 1024 42 43 // DefaultNetworkChunkSize - how much data request per 1 network call to peer. 44 // default: 16Kb 45 const DefaultNetworkChunkSize = 512 * 1024 46 47 type Cfg struct { 48 ClientConfig *torrent.ClientConfig 49 SnapDir string 50 DownloadSlots int 51 WebSeedUrls []*url.URL 52 WebSeedFiles []string 53 } 54 55 func Default() *torrent.ClientConfig { 56 torrentConfig := torrent.NewDefaultClientConfig() 57 58 // enable dht 59 torrentConfig.NoDHT = true 60 //torrentConfig.DisableTrackers = true 61 //torrentConfig.DisableWebtorrent = true 62 63 // Reduce defaults - to avoid peers with very bad geography 64 //torrentConfig.MinDialTimeout = 1 * time.Second // default: 3sec 65 //torrentConfig.NominalDialTimeout = 10 * time.Second // default: 20sec 66 //torrentConfig.HandshakesTimeout = 1 * time.Second // default: 4sec 67 68 // see: https://en.wikipedia.org/wiki/TCP_half-open 69 //torrentConfig.TotalHalfOpenConns = 100 // default: 100 70 //torrentConfig.HalfOpenConnsPerTorrent = 25 // default: 25 71 //torrentConfig.TorrentPeersHighWater = 500 // default: 500 72 //torrentConfig.TorrentPeersLowWater = 50 // default: 50 73 74 torrentConfig.Seed = true 75 torrentConfig.UpnpID = torrentConfig.UpnpID + "leecher" 76 77 return torrentConfig 78 } 79 80 func New(dataDir datadir.Dirs, version string, verbosity lg.Level, downloadRate, uploadRate datasize.ByteSize, port, connsPerFile, downloadSlots int, staticPeers []string, webseeds string) (*Cfg, error) { 81 torrentConfig := Default() 82 torrentConfig.DataDir = dataDir.Snap // `DataDir` of torrent-client-lib is different from Erigon's `DataDir`. Just same naming. 83 84 torrentConfig.ExtendedHandshakeClientVersion = version 85 86 // We would-like to reduce amount of goroutines in Erigon, so reducing next params 87 torrentConfig.EstablishedConnsPerTorrent = connsPerFile // default: 50 88 89 torrentConfig.ListenPort = port 90 // check if ipv6 is enabled 91 torrentConfig.DisableIPv6 = !getIpv6Enabled() 92 93 // rates are divided by 2 - I don't know why it works, maybe bug inside torrent lib accounting 94 torrentConfig.UploadRateLimiter = rate.NewLimiter(rate.Limit(uploadRate.Bytes()), 2*DefaultNetworkChunkSize) // default: unlimited 95 if downloadRate.Bytes() < 500_000_000 { 96 b := 2 * DefaultNetworkChunkSize 97 if downloadRate.Bytes() > DefaultNetworkChunkSize { 98 b = int(2 * downloadRate.Bytes()) 99 } 100 torrentConfig.DownloadRateLimiter = rate.NewLimiter(rate.Limit(downloadRate.Bytes()), b) // default: unlimited 101 } 102 103 // debug 104 // torrentConfig.Debug = false 105 torrentConfig.Logger.WithFilterLevel(verbosity) 106 torrentConfig.Logger.Handlers = []lg.Handler{adapterHandler{}} 107 108 if len(staticPeers) > 0 { 109 torrentConfig.NoDHT = false 110 //defaultNodes := torrentConfig.DhtStartingNodes 111 torrentConfig.DhtStartingNodes = func(network string) dht.StartingNodesGetter { 112 return func() ([]dht.Addr, error) { 113 addrs, err := dht.GlobalBootstrapAddrs(network) 114 if err != nil { 115 return nil, err 116 } 117 118 for _, seed := range staticPeers { 119 if network == "udp" { 120 var addr *net.UDPAddr 121 addr, err := net.ResolveUDPAddr(network, seed+":80") 122 if err != nil { 123 log.Warn("[downloader] Cannot UDP resolve address", "network", network, "addr", seed) 124 continue 125 } 126 addrs = append(addrs, dht.NewAddr(addr)) 127 } 128 if network == "tcp" { 129 var addr *net.TCPAddr 130 addr, err := net.ResolveTCPAddr(network, seed+":80") 131 if err != nil { 132 log.Warn("[downloader] Cannot TCP resolve address", "network", network, "addr", seed) 133 continue 134 } 135 addrs = append(addrs, dht.NewAddr(addr)) 136 } 137 } 138 return addrs, nil 139 } 140 } 141 //staticPeers 142 } 143 144 webseedUrlsOrFiles := common.CliString2Array(webseeds) 145 webseedUrls := make([]*url.URL, 0, len(webseedUrlsOrFiles)) 146 webseedFiles := make([]string, 0, len(webseedUrlsOrFiles)) 147 for _, webseed := range webseedUrlsOrFiles { 148 uri, err := url.ParseRequestURI(webseed) 149 if err != nil { 150 if strings.HasSuffix(webseed, ".toml") && dir.FileExist(webseed) { 151 webseedFiles = append(webseedFiles, webseed) 152 } 153 continue 154 } 155 webseedUrls = append(webseedUrls, uri) 156 } 157 localCfgFile := filepath.Join(dataDir.DataDir, "webseeds.toml") // datadir/webseeds.toml allowed 158 if dir.FileExist(localCfgFile) { 159 webseedFiles = append(webseedFiles, localCfgFile) 160 } 161 162 return &Cfg{SnapDir: torrentConfig.DataDir, 163 ClientConfig: torrentConfig, DownloadSlots: downloadSlots, 164 WebSeedUrls: webseedUrls, WebSeedFiles: webseedFiles, 165 }, nil 166 } 167 168 func getIpv6Enabled() bool { 169 if runtime.GOOS == "linux" { 170 file, err := ioutil.ReadFile("/sys/module/ipv6/parameters/disable") 171 if err != nil { 172 log.Warn("could not read /sys/module/ipv6/parameters/disable for ipv6 detection") 173 return false 174 } 175 fileContent := strings.TrimSpace(string(file)) 176 return fileContent != "0" 177 } 178 179 // TODO hotfix: for platforms other than linux disable ipv6 180 return false 181 }