github.com/igggame/nebulas-go@v2.1.0+incompatible/net/route_table.go (about) 1 // Copyright (C) 2018 go-nebulas authors 2 // 3 // This file is part of the go-nebulas library. 4 // 5 // the go-nebulas library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // the go-nebulas library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 19 package net 20 21 import ( 22 "bufio" 23 "errors" 24 "fmt" 25 "math/rand" 26 "os" 27 "path" 28 "reflect" 29 "strings" 30 "time" 31 32 "github.com/sirupsen/logrus" 33 34 "github.com/multiformats/go-multiaddr" 35 netpb "github.com/nebulasio/go-nebulas/net/pb" 36 "github.com/nebulasio/go-nebulas/util/logging" 37 38 kbucket "github.com/libp2p/go-libp2p-kbucket" 39 peer "github.com/libp2p/go-libp2p-peer" 40 peerstore "github.com/libp2p/go-libp2p-peerstore" 41 ma "github.com/multiformats/go-multiaddr" 42 ) 43 44 // Route Table Errors 45 var ( 46 ErrExceedMaxSyncRouteResponse = errors.New("too many sync route table response") 47 ) 48 49 // RouteTable route table struct. 50 type RouteTable struct { 51 quitCh chan bool 52 peerStore peerstore.Peerstore 53 routeTable *kbucket.RoutingTable 54 maxPeersCountForSyncResp int 55 maxPeersCountToSync int 56 cacheFilePath string 57 seedNodes []ma.Multiaddr 58 node *Node 59 streamManager *StreamManager 60 latestUpdatedAt int64 61 internalNodeList []string 62 } 63 64 // NewRouteTable new route table. 65 func NewRouteTable(config *Config, node *Node) *RouteTable { 66 table := &RouteTable{ 67 quitCh: make(chan bool, 1), 68 peerStore: peerstore.NewPeerstore(), 69 maxPeersCountForSyncResp: MaxPeersCountForSyncResp, 70 maxPeersCountToSync: config.MaxSyncNodes, 71 cacheFilePath: path.Join(config.RoutingTableDir, RouteTableCacheFileName), 72 seedNodes: config.BootNodes, 73 node: node, 74 streamManager: node.streamManager, 75 latestUpdatedAt: 0, 76 } 77 78 table.routeTable = kbucket.NewRoutingTable( 79 config.Bucketsize, 80 kbucket.ConvertPeerID(node.id), 81 config.Latency, 82 table.peerStore, 83 ) 84 85 table.routeTable.Update(node.id) 86 table.peerStore.AddPubKey(node.id, node.networkKey.GetPublic()) 87 table.peerStore.AddPrivKey(node.id, node.networkKey) 88 89 return table 90 } 91 92 // Start start route table syncLoop. 93 func (table *RouteTable) Start() { 94 logging.CLog().Info("Starting NebService RouteTable Sync...") 95 96 go table.syncLoop() 97 } 98 99 // Stop quit route table syncLoop. 100 func (table *RouteTable) Stop() { 101 logging.CLog().Info("Stopping NebService RouteTable Sync...") 102 103 table.quitCh <- true 104 } 105 106 // Peers return peers in route table. 107 func (table *RouteTable) Peers() map[peer.ID][]ma.Multiaddr { 108 peers := make(map[peer.ID][]ma.Multiaddr) 109 for _, pid := range table.peerStore.Peers() { 110 peers[pid] = table.peerStore.Addrs(pid) 111 } 112 return peers 113 } 114 115 func (table *RouteTable) syncLoop() { 116 // Load Route Table. 117 table.LoadSeedNodes() 118 table.LoadRouteTableFromFile() 119 table.LoadInternalNodeList() 120 121 // trigger first sync. 122 table.SyncRouteTable() 123 124 logging.CLog().Info("Started NebService RouteTable Sync.") 125 126 syncLoopTicker := time.NewTicker(RouteTableSyncLoopInterval) 127 saveRouteTableToDiskTicker := time.NewTicker(RouteTableSaveToDiskInterval) 128 latestUpdatedAt := table.latestUpdatedAt 129 130 for { 131 select { 132 case <-table.quitCh: 133 logging.CLog().Info("Stopped NebService RouteTable Sync.") 134 return 135 case <-syncLoopTicker.C: 136 table.SyncRouteTable() 137 case <-saveRouteTableToDiskTicker.C: 138 if latestUpdatedAt < table.latestUpdatedAt { 139 table.SaveRouteTableToFile() 140 latestUpdatedAt = table.latestUpdatedAt 141 } 142 } 143 } 144 } 145 146 // AddPeerInfo add peer to route table. 147 func (table *RouteTable) AddPeerInfo(prettyID string, addrStr []string) error { 148 pid, err := peer.IDB58Decode(prettyID) 149 if err != nil { 150 return nil 151 } 152 153 addrs := make([]ma.Multiaddr, len(addrStr)) 154 for i, v := range addrStr { 155 addrs[i], err = multiaddr.NewMultiaddr(v) 156 if err != nil { 157 return err 158 } 159 } 160 161 if table.routeTable.Find(pid) != "" { 162 table.peerStore.SetAddrs(pid, addrs, peerstore.PermanentAddrTTL) 163 } else { 164 table.peerStore.AddAddrs(pid, addrs, peerstore.PermanentAddrTTL) 165 } 166 table.routeTable.Update(pid) 167 table.onRouteTableChange() 168 169 return nil 170 } 171 172 // AddPeer add peer to route table. 173 func (table *RouteTable) AddPeer(pid peer.ID, addr ma.Multiaddr) { 174 logging.VLog().Debugf("Adding Peer: %s,%s", pid.Pretty(), addr.String()) 175 table.peerStore.AddAddr(pid, addr, peerstore.PermanentAddrTTL) 176 table.routeTable.Update(pid) 177 table.onRouteTableChange() 178 179 } 180 181 // AddPeers add peers to route table 182 func (table *RouteTable) AddPeers(pid string, peers *netpb.Peers) { 183 // recv too many peers info. say Bye. 184 if len(peers.Peers) > table.maxPeersCountForSyncResp { 185 table.streamManager.CloseStream(pid, ErrExceedMaxSyncRouteResponse) 186 } 187 for _, v := range peers.Peers { 188 table.AddPeerInfo(v.Id, v.Addrs) 189 } 190 } 191 192 // AddIPFSPeerAddr add a peer to route table with ipfs address. 193 func (table *RouteTable) AddIPFSPeerAddr(addr ma.Multiaddr) { 194 id, addr, err := ParseFromIPFSAddr(addr) 195 if err != nil { 196 return 197 } 198 table.AddPeer(id, addr) 199 } 200 201 // AddPeerStream add peer stream to peerStore. 202 func (table *RouteTable) AddPeerStream(s *Stream) { 203 table.peerStore.AddAddr( 204 s.pid, 205 s.addr, 206 peerstore.PermanentAddrTTL, 207 ) 208 table.routeTable.Update(s.pid) 209 table.onRouteTableChange() 210 } 211 212 // RemovePeerStream remove peerStream from peerStore. 213 func (table *RouteTable) RemovePeerStream(s *Stream) { 214 table.peerStore.AddAddr(s.pid, s.addr, 0) 215 table.routeTable.Remove(s.pid) 216 table.onRouteTableChange() 217 } 218 219 func (table *RouteTable) onRouteTableChange() { 220 table.latestUpdatedAt = time.Now().Unix() 221 } 222 223 // GetRandomPeers get random peers 224 func (table *RouteTable) GetRandomPeers(pid peer.ID) []peerstore.PeerInfo { 225 226 // change sync route algorithm from `NearestPeers` to `randomPeers` 227 var peers []peer.ID 228 allPeers := table.routeTable.ListPeers() 229 // Do not accept internal node synchronization routing requests. 230 if inArray(pid.Pretty(), table.internalNodeList) { 231 return []peerstore.PeerInfo{} 232 } 233 234 for _, v := range allPeers { 235 if inArray(v.Pretty(), table.internalNodeList) == false { 236 peers = append(peers, v) 237 } 238 } 239 peers = shufflePeerID(peers) 240 if len(peers) > table.maxPeersCountForSyncResp { 241 peers = peers[:table.maxPeersCountForSyncResp] 242 } 243 ret := make([]peerstore.PeerInfo, len(peers)) 244 for i, v := range peers { 245 ret[i] = table.peerStore.PeerInfo(v) 246 } 247 return ret 248 } 249 250 func inArray(obj interface{}, array interface{}) bool { 251 arrayValue := reflect.ValueOf(array) 252 if reflect.TypeOf(array).Kind() == reflect.Array || reflect.TypeOf(array).Kind() == reflect.Slice { 253 for i := 0; i < arrayValue.Len(); i++ { 254 if arrayValue.Index(i).Interface() == obj { 255 return true 256 } 257 } 258 } 259 return false 260 } 261 262 func shufflePeerID(pids []peer.ID) []peer.ID { 263 264 r := rand.New(rand.NewSource(time.Now().Unix())) 265 ret := make([]peer.ID, len(pids)) 266 perm := r.Perm(len(pids)) 267 for i, randIndex := range perm { 268 ret[i] = pids[randIndex] 269 } 270 return ret 271 } 272 273 // LoadSeedNodes load seed nodes. 274 func (table *RouteTable) LoadSeedNodes() { 275 for _, ipfsAddr := range table.seedNodes { 276 table.AddIPFSPeerAddr(ipfsAddr) 277 } 278 } 279 280 // LoadRouteTableFromFile load route table from file. 281 func (table *RouteTable) LoadRouteTableFromFile() { 282 file, err := os.Open(table.cacheFilePath) 283 if err != nil { 284 logging.VLog().WithFields(logrus.Fields{ 285 "cacheFilePath": table.cacheFilePath, 286 "err": err, 287 }).Warn("Failed to open Route Table Cache file.") 288 return 289 } 290 defer file.Close() 291 292 // read line by line. 293 scanner := bufio.NewScanner(file) 294 scanner.Split(bufio.ScanLines) 295 296 for scanner.Scan() { 297 line := strings.TrimSpace(scanner.Text()) 298 if strings.HasPrefix(line, "#") { 299 continue 300 } 301 302 addr, err := ma.NewMultiaddr(line) 303 if err != nil { 304 // ignore. 305 logging.VLog().WithFields(logrus.Fields{ 306 "err": err, 307 "text": line, 308 }).Warn("Invalid address in Route Table Cache file.") 309 continue 310 } 311 312 table.AddIPFSPeerAddr(addr) 313 } 314 } 315 316 // SaveRouteTableToFile save route table to file. 317 func (table *RouteTable) SaveRouteTableToFile() { 318 file, err := os.Create(table.cacheFilePath) 319 if err != nil { 320 logging.VLog().WithFields(logrus.Fields{ 321 "cacheFilePath": table.cacheFilePath, 322 "err": err, 323 }).Warn("Failed to open Route Table Cache file.") 324 return 325 } 326 defer file.Close() 327 328 // write header. 329 file.WriteString(fmt.Sprintf("# %s\n", time.Now().String())) 330 331 peers := table.routeTable.ListPeers() 332 for _, v := range peers { 333 for _, addr := range table.peerStore.Addrs(v) { 334 line := fmt.Sprintf("%s/ipfs/%s\n", addr, v.Pretty()) 335 file.WriteString(line) 336 } 337 } 338 } 339 340 // SyncRouteTable sync route table. 341 func (table *RouteTable) SyncRouteTable() { 342 syncedPeers := make(map[peer.ID]bool) 343 344 // sync with seed nodes. 345 for _, ipfsAddr := range table.seedNodes { 346 pid, _, err := ParseFromIPFSAddr(ipfsAddr) 347 if err != nil { 348 continue 349 } 350 table.SyncWithPeer(pid) 351 syncedPeers[pid] = true 352 } 353 354 // random peer selection. 355 peers := table.routeTable.ListPeers() 356 peersCount := len(peers) 357 if peersCount <= 1 { 358 return 359 } 360 361 peersCountToSync := table.maxPeersCountToSync 362 363 if peersCount < peersCountToSync { 364 peersCountToSync = peersCount 365 } 366 selectedPeersIdx := make(map[int]bool) 367 for i := 0; i < peersCountToSync/2; i++ { 368 ri := 0 369 370 for { 371 ri = rand.Intn(peersCountToSync) 372 if selectedPeersIdx[ri] == false { 373 break 374 } 375 } 376 377 selectedPeersIdx[ri] = true 378 pid := peers[ri] 379 380 if syncedPeers[pid] == false { 381 table.SyncWithPeer(pid) 382 syncedPeers[pid] = true 383 } 384 } 385 } 386 387 // SyncWithPeer sync route table with a peer. 388 func (table *RouteTable) SyncWithPeer(pid peer.ID) { 389 if pid == table.node.id { 390 return 391 } 392 393 stream := table.streamManager.Find(pid) 394 395 if stream == nil { 396 stream = NewStreamFromPID(pid, table.node) 397 table.streamManager.AddStream(stream) 398 } 399 400 stream.SyncRoute() 401 } 402 403 //LoadInternalNodeList Load Internal Node list from file 404 func (table *RouteTable) LoadInternalNodeList() { 405 file, err := os.Open(RouteTableInternalNodeFileName) 406 if err != nil { 407 logging.VLog().WithFields(logrus.Fields{ 408 "err": err, 409 }).Warn("Failed to open internal list file.") 410 return 411 } 412 defer file.Close() 413 414 // read line by line. 415 scanner := bufio.NewScanner(file) 416 scanner.Split(bufio.ScanLines) 417 418 for scanner.Scan() { 419 line := strings.TrimSpace(scanner.Text()) 420 if len(line) > 0 { 421 table.internalNodeList = append(table.internalNodeList, line) 422 } 423 } 424 425 logging.VLog().WithFields(logrus.Fields{ 426 "internalNodeList": table.internalNodeList, 427 }).Info("Loaded internal node list.") 428 }