github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/network/hive.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The go-ethereum library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package network 18 19 import ( 20 "fmt" 21 "sync" 22 "time" 23 24 "github.com/FusionFoundation/efsn/common/hexutil" 25 "github.com/FusionFoundation/efsn/p2p" 26 "github.com/FusionFoundation/efsn/p2p/discover" 27 "github.com/FusionFoundation/efsn/swarm/log" 28 "github.com/FusionFoundation/efsn/swarm/state" 29 ) 30 31 /* 32 Hive is the logistic manager of the swarm 33 34 When the hive is started, a forever loop is launched that 35 asks the kademlia nodetable 36 to suggest peers to bootstrap connectivity 37 */ 38 39 // HiveParams holds the config options to hive 40 type HiveParams struct { 41 Discovery bool // if want discovery of not 42 PeersBroadcastSetSize uint8 // how many peers to use when relaying 43 MaxPeersPerRequest uint8 // max size for peer address batches 44 KeepAliveInterval time.Duration 45 } 46 47 // NewHiveParams returns hive config with only the 48 func NewHiveParams() *HiveParams { 49 return &HiveParams{ 50 Discovery: true, 51 PeersBroadcastSetSize: 3, 52 MaxPeersPerRequest: 5, 53 KeepAliveInterval: 500 * time.Millisecond, 54 } 55 } 56 57 // Hive manages network connections of the swarm node 58 type Hive struct { 59 *HiveParams // settings 60 *Kademlia // the overlay connectiviy driver 61 Store state.Store // storage interface to save peers across sessions 62 addPeer func(*discover.Node) // server callback to connect to a peer 63 // bookkeeping 64 lock sync.Mutex 65 ticker *time.Ticker 66 } 67 68 // NewHive constructs a new hive 69 // HiveParams: config parameters 70 // Kademlia: connectivity driver using a network topology 71 // StateStore: to save peers across sessions 72 func NewHive(params *HiveParams, kad *Kademlia, store state.Store) *Hive { 73 return &Hive{ 74 HiveParams: params, 75 Kademlia: kad, 76 Store: store, 77 } 78 } 79 80 // Start stars the hive, receives p2p.Server only at startup 81 // server is used to connect to a peer based on its NodeID or enode URL 82 // these are called on the p2p.Server which runs on the node 83 func (h *Hive) Start(server *p2p.Server) error { 84 log.Info("Starting hive", "baseaddr", fmt.Sprintf("%x", h.BaseAddr()[:4])) 85 // if state store is specified, load peers to prepopulate the overlay address book 86 if h.Store != nil { 87 log.Info("Detected an existing store. trying to load peers") 88 if err := h.loadPeers(); err != nil { 89 log.Error(fmt.Sprintf("%08x hive encoutered an error trying to load peers", h.BaseAddr()[:4])) 90 return err 91 } 92 } 93 // assigns the p2p.Server#AddPeer function to connect to peers 94 h.addPeer = server.AddPeer 95 // ticker to keep the hive alive 96 h.ticker = time.NewTicker(h.KeepAliveInterval) 97 // this loop is doing bootstrapping and maintains a healthy table 98 go h.connect() 99 return nil 100 } 101 102 // Stop terminates the updateloop and saves the peers 103 func (h *Hive) Stop() error { 104 log.Info(fmt.Sprintf("%08x hive stopping, saving peers", h.BaseAddr()[:4])) 105 h.ticker.Stop() 106 if h.Store != nil { 107 if err := h.savePeers(); err != nil { 108 return fmt.Errorf("could not save peers to persistence store: %v", err) 109 } 110 if err := h.Store.Close(); err != nil { 111 return fmt.Errorf("could not close file handle to persistence store: %v", err) 112 } 113 } 114 log.Info(fmt.Sprintf("%08x hive stopped, dropping peers", h.BaseAddr()[:4])) 115 h.EachConn(nil, 255, func(p *Peer, _ int, _ bool) bool { 116 log.Info(fmt.Sprintf("%08x dropping peer %08x", h.BaseAddr()[:4], p.Address()[:4])) 117 p.Drop(nil) 118 return true 119 }) 120 121 log.Info(fmt.Sprintf("%08x all peers dropped", h.BaseAddr()[:4])) 122 return nil 123 } 124 125 // connect is a forever loop 126 // at each iteration, ask the overlay driver to suggest the most preferred peer to connect to 127 // as well as advertises saturation depth if needed 128 func (h *Hive) connect() { 129 for range h.ticker.C { 130 131 addr, depth, changed := h.SuggestPeer() 132 if h.Discovery && changed { 133 NotifyDepth(uint8(depth), h.Kademlia) 134 } 135 if addr == nil { 136 continue 137 } 138 139 log.Trace(fmt.Sprintf("%08x hive connect() suggested %08x", h.BaseAddr()[:4], addr.Address()[:4])) 140 under, err := discover.ParseNode(string(addr.Under())) 141 if err != nil { 142 log.Warn(fmt.Sprintf("%08x unable to connect to bee %08x: invalid node URL: %v", h.BaseAddr()[:4], addr.Address()[:4], err)) 143 continue 144 } 145 log.Trace(fmt.Sprintf("%08x attempt to connect to bee %08x", h.BaseAddr()[:4], addr.Address()[:4])) 146 h.addPeer(under) 147 } 148 } 149 150 // Run protocol run function 151 func (h *Hive) Run(p *BzzPeer) error { 152 dp := NewPeer(p, h.Kademlia) 153 depth, changed := h.On(dp) 154 // if we want discovery, advertise change of depth 155 if h.Discovery { 156 if changed { 157 // if depth changed, send to all peers 158 NotifyDepth(depth, h.Kademlia) 159 } else { 160 // otherwise just send depth to new peer 161 dp.NotifyDepth(depth) 162 } 163 } 164 NotifyPeer(p.BzzAddr, h.Kademlia) 165 defer h.Off(dp) 166 return dp.Run(dp.HandleMsg) 167 } 168 169 // NodeInfo function is used by the p2p.server RPC interface to display 170 // protocol specific node information 171 func (h *Hive) NodeInfo() interface{} { 172 return h.String() 173 } 174 175 // PeerInfo function is used by the p2p.server RPC interface to display 176 // protocol specific information any connected peer referred to by their NodeID 177 func (h *Hive) PeerInfo(id discover.NodeID) interface{} { 178 addr := NewAddrFromNodeID(id) 179 return struct { 180 OAddr hexutil.Bytes 181 UAddr hexutil.Bytes 182 }{ 183 OAddr: addr.OAddr, 184 UAddr: addr.UAddr, 185 } 186 } 187 188 // loadPeers, savePeer implement persistence callback/ 189 func (h *Hive) loadPeers() error { 190 var as []*BzzAddr 191 err := h.Store.Get("peers", &as) 192 if err != nil { 193 if err == state.ErrNotFound { 194 log.Info(fmt.Sprintf("hive %08x: no persisted peers found", h.BaseAddr()[:4])) 195 return nil 196 } 197 return err 198 } 199 log.Info(fmt.Sprintf("hive %08x: peers loaded", h.BaseAddr()[:4])) 200 201 return h.Register(as...) 202 } 203 204 // savePeers, savePeer implement persistence callback/ 205 func (h *Hive) savePeers() error { 206 var peers []*BzzAddr 207 h.Kademlia.EachAddr(nil, 256, func(pa *BzzAddr, i int, _ bool) bool { 208 if pa == nil { 209 log.Warn(fmt.Sprintf("empty addr: %v", i)) 210 return true 211 } 212 log.Trace("saving peer", "peer", pa) 213 peers = append(peers, pa) 214 return true 215 }) 216 if err := h.Store.Put("peers", peers); err != nil { 217 return fmt.Errorf("could not save peers: %v", err) 218 } 219 return nil 220 }