2022-11-20 03:41:20 +00:00
/ *
Copyright 2021 Erigon contributors
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package downloadercfg
import (
2022-11-24 13:43:41 +00:00
"io/ioutil"
2023-03-08 08:29:42 +00:00
"net"
2023-09-12 05:18:39 +00:00
"net/url"
"path/filepath"
2022-11-24 13:43:41 +00:00
"runtime"
2022-11-20 03:41:20 +00:00
"strings"
2023-10-14 10:11:39 +00:00
"time"
2022-11-20 03:41:20 +00:00
2023-03-08 08:29:42 +00:00
"github.com/anacrolix/dht/v2"
2022-11-20 03:41:20 +00:00
lg "github.com/anacrolix/log"
"github.com/anacrolix/torrent"
"github.com/c2h5oh/datasize"
2023-11-13 13:10:57 +00:00
"github.com/ledgerwatch/erigon-lib/chain/snapcfg"
2023-09-12 05:18:39 +00:00
"github.com/ledgerwatch/erigon-lib/common/datadir"
"github.com/ledgerwatch/erigon-lib/common/dir"
2022-11-20 03:41:20 +00:00
"github.com/ledgerwatch/log/v3"
"golang.org/x/time/rate"
)
// DefaultPieceSize - Erigon serves many big files, bigger pieces will reduce
// amount of network announcements, but can't go over 2Mb
// see https://wiki.theory.org/BitTorrentSpecification#Metainfo_File_Structure
const DefaultPieceSize = 2 * 1024 * 1024
// DefaultNetworkChunkSize - how much data request per 1 network call to peer.
// default: 16Kb
2023-10-11 09:18:21 +00:00
const DefaultNetworkChunkSize = 256 * 1024
2022-11-20 03:41:20 +00:00
type Cfg struct {
2023-09-12 05:18:39 +00:00
ClientConfig * torrent . ClientConfig
2022-11-20 03:41:20 +00:00
DownloadSlots int
2023-10-13 11:03:52 +00:00
WebSeedUrls [ ] * url . URL
WebSeedFiles [ ] string
2023-10-18 07:24:09 +00:00
WebSeedS3Tokens [ ] string
2023-11-24 11:46:17 +00:00
ExpectedTorrentFilesHashes snapcfg . Preverified
2023-10-13 11:03:52 +00:00
DownloadTorrentFilesFromWebseed bool
2023-10-18 07:24:09 +00:00
ChainName string
2023-10-13 11:03:52 +00:00
Dirs datadir . Dirs
2022-11-20 03:41:20 +00:00
}
func Default ( ) * torrent . ClientConfig {
torrentConfig := torrent . NewDefaultClientConfig ( )
2023-11-01 16:22:35 +00:00
// better don't increase because erigon periodically producing "new seedable files" - and adding them to downloader.
// it must not impact chain tip sync - so, limit resources to minimum by default.
// but when downloader is started as a separated process - rise it to max
//torrentConfig.PieceHashersPerTorrent = cmp.Max(1, runtime.NumCPU()-1)
2022-11-20 03:41:20 +00:00
2023-10-14 10:11:39 +00:00
torrentConfig . MinDialTimeout = 6 * time . Second //default: 3s
torrentConfig . HandshakesTimeout = 8 * time . Second //default: 4s
2022-11-20 03:41:20 +00:00
// enable dht
torrentConfig . NoDHT = true
//torrentConfig.DisableTrackers = true
//torrentConfig.DisableWebtorrent = true
// Reduce defaults - to avoid peers with very bad geography
//torrentConfig.MinDialTimeout = 1 * time.Second // default: 3sec
//torrentConfig.NominalDialTimeout = 10 * time.Second // default: 20sec
//torrentConfig.HandshakesTimeout = 1 * time.Second // default: 4sec
// see: https://en.wikipedia.org/wiki/TCP_half-open
//torrentConfig.TotalHalfOpenConns = 100 // default: 100
//torrentConfig.HalfOpenConnsPerTorrent = 25 // default: 25
//torrentConfig.TorrentPeersHighWater = 500 // default: 500
//torrentConfig.TorrentPeersLowWater = 50 // default: 50
torrentConfig . Seed = true
torrentConfig . UpnpID = torrentConfig . UpnpID + "leecher"
return torrentConfig
}
2023-10-18 07:24:09 +00:00
func New ( dirs datadir . Dirs , version string , verbosity lg . Level , downloadRate , uploadRate datasize . ByteSize , port , connsPerFile , downloadSlots int , staticPeers , webseeds [ ] string , chainName string ) ( * Cfg , error ) {
2022-11-20 03:41:20 +00:00
torrentConfig := Default ( )
2023-10-04 04:01:02 +00:00
torrentConfig . DataDir = dirs . Snap // `DataDir` of torrent-client-lib is different from Erigon's `DataDir`. Just same naming.
2023-09-12 05:18:39 +00:00
2022-11-20 03:41:20 +00:00
torrentConfig . ExtendedHandshakeClientVersion = version
// We would-like to reduce amount of goroutines in Erigon, so reducing next params
torrentConfig . EstablishedConnsPerTorrent = connsPerFile // default: 50
torrentConfig . ListenPort = port
// check if ipv6 is enabled
2022-11-24 13:43:41 +00:00
torrentConfig . DisableIPv6 = ! getIpv6Enabled ( )
2022-11-20 03:41:20 +00:00
2023-10-11 09:18:21 +00:00
torrentConfig . UploadRateLimiter = rate . NewLimiter ( rate . Limit ( uploadRate . Bytes ( ) ) , DefaultNetworkChunkSize ) // default: unlimited
2022-11-20 03:41:20 +00:00
if downloadRate . Bytes ( ) < 500_000_000 {
2023-10-11 09:18:21 +00:00
torrentConfig . DownloadRateLimiter = rate . NewLimiter ( rate . Limit ( downloadRate . Bytes ( ) ) , DefaultNetworkChunkSize ) // default: unlimited
2022-11-20 03:41:20 +00:00
}
// debug
2023-10-14 10:11:39 +00:00
//torrentConfig.Debug = true
torrentConfig . Logger = torrentConfig . Logger . WithFilterLevel ( verbosity )
torrentConfig . Logger . SetHandlers ( adapterHandler { } )
2022-11-20 03:41:20 +00:00
2023-03-08 08:29:42 +00:00
if len ( staticPeers ) > 0 {
torrentConfig . NoDHT = false
//defaultNodes := torrentConfig.DhtStartingNodes
torrentConfig . DhtStartingNodes = func ( network string ) dht . StartingNodesGetter {
return func ( ) ( [ ] dht . Addr , error ) {
addrs , err := dht . GlobalBootstrapAddrs ( network )
if err != nil {
return nil , err
}
for _ , seed := range staticPeers {
if network == "udp" {
var addr * net . UDPAddr
addr , err := net . ResolveUDPAddr ( network , seed + ":80" )
if err != nil {
log . Warn ( "[downloader] Cannot UDP resolve address" , "network" , network , "addr" , seed )
continue
}
addrs = append ( addrs , dht . NewAddr ( addr ) )
}
if network == "tcp" {
var addr * net . TCPAddr
addr , err := net . ResolveTCPAddr ( network , seed + ":80" )
if err != nil {
log . Warn ( "[downloader] Cannot TCP resolve address" , "network" , network , "addr" , seed )
continue
}
addrs = append ( addrs , dht . NewAddr ( addr ) )
}
}
return addrs , nil
}
}
//staticPeers
}
2023-10-18 07:24:09 +00:00
webseedUrlsOrFiles := webseeds
webseedHttpProviders := make ( [ ] * url . URL , 0 , len ( webseedUrlsOrFiles ) )
webseedFileProviders := make ( [ ] string , 0 , len ( webseedUrlsOrFiles ) )
webseedS3Providers := make ( [ ] string , 0 , len ( webseedUrlsOrFiles ) )
2023-09-12 05:18:39 +00:00
for _ , webseed := range webseedUrlsOrFiles {
2023-10-18 07:24:09 +00:00
if strings . HasPrefix ( webseed , "v" ) { // has marker v1/v2/...
webseedS3Providers = append ( webseedS3Providers , webseed )
continue
}
2023-09-12 05:18:39 +00:00
uri , err := url . ParseRequestURI ( webseed )
if err != nil {
if strings . HasSuffix ( webseed , ".toml" ) && dir . FileExist ( webseed ) {
2023-10-18 07:24:09 +00:00
webseedFileProviders = append ( webseedFileProviders , webseed )
2023-09-12 05:18:39 +00:00
}
continue
}
2023-10-18 07:24:09 +00:00
webseedHttpProviders = append ( webseedHttpProviders , uri )
2023-09-12 05:18:39 +00:00
}
2023-10-13 11:03:52 +00:00
localCfgFile := filepath . Join ( dirs . DataDir , "webseed.toml" ) // datadir/webseed.toml allowed
2023-09-12 05:18:39 +00:00
if dir . FileExist ( localCfgFile ) {
2023-10-18 07:24:09 +00:00
webseedFileProviders = append ( webseedFileProviders , localCfgFile )
2023-09-12 05:18:39 +00:00
}
2023-11-24 11:46:17 +00:00
//TODO: if don't pass "downloaded files list here" (which we store in db) - synced erigon will download new .torrent files. And erigon can't work with "unfinished" files.
snapCfg := snapcfg . KnownCfg ( chainName , nil , nil )
2023-10-18 07:24:09 +00:00
return & Cfg { Dirs : dirs , ChainName : chainName ,
2023-09-12 05:18:39 +00:00
ClientConfig : torrentConfig , DownloadSlots : downloadSlots ,
2023-10-18 07:24:09 +00:00
WebSeedUrls : webseedHttpProviders , WebSeedFiles : webseedFileProviders , WebSeedS3Tokens : webseedS3Providers ,
2023-11-24 11:46:17 +00:00
DownloadTorrentFilesFromWebseed : false , ExpectedTorrentFilesHashes : snapCfg . Preverified ,
2023-09-12 05:18:39 +00:00
} , nil
2022-11-20 03:41:20 +00:00
}
2022-11-24 13:43:41 +00:00
func getIpv6Enabled ( ) bool {
if runtime . GOOS == "linux" {
file , err := ioutil . ReadFile ( "/sys/module/ipv6/parameters/disable" )
if err != nil {
log . Warn ( "could not read /sys/module/ipv6/parameters/disable for ipv6 detection" )
return false
}
fileContent := strings . TrimSpace ( string ( file ) )
return fileContent != "0"
}
// TODO hotfix: for platforms other than linux disable ipv6
return false
}