github.com/gobitfly/go-ethereum@v1.8.12/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/ethereum/go-ethereum/common/hexutil" 25 "github.com/ethereum/go-ethereum/p2p" 26 "github.com/ethereum/go-ethereum/p2p/discover" 27 "github.com/ethereum/go-ethereum/swarm/log" 28 "github.com/ethereum/go-ethereum/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 Overlay Topology driver (e.g., generic kademlia nodetable) 36 to suggest peers to bootstrap connectivity 37 */ 38 39 // Overlay is the interface for kademlia (or other topology drivers) 40 type Overlay interface { 41 // suggest peers to connect to 42 SuggestPeer() (OverlayAddr, int, bool) 43 // register and deregister peer connections 44 On(OverlayConn) (depth uint8, changed bool) 45 Off(OverlayConn) 46 // register peer addresses 47 Register([]OverlayAddr) error 48 // iterate over connected peers 49 EachConn([]byte, int, func(OverlayConn, int, bool) bool) 50 // iterate over known peers (address records) 51 EachAddr([]byte, int, func(OverlayAddr, int, bool) bool) 52 // pretty print the connectivity 53 String() string 54 // base Overlay address of the node itself 55 BaseAddr() []byte 56 // connectivity health check used for testing 57 Healthy(*PeerPot) *Health 58 } 59 60 // HiveParams holds the config options to hive 61 type HiveParams struct { 62 Discovery bool // if want discovery of not 63 PeersBroadcastSetSize uint8 // how many peers to use when relaying 64 MaxPeersPerRequest uint8 // max size for peer address batches 65 KeepAliveInterval time.Duration 66 } 67 68 // NewHiveParams returns hive config with only the 69 func NewHiveParams() *HiveParams { 70 return &HiveParams{ 71 Discovery: true, 72 PeersBroadcastSetSize: 3, 73 MaxPeersPerRequest: 5, 74 KeepAliveInterval: 500 * time.Millisecond, 75 } 76 } 77 78 // Hive manages network connections of the swarm node 79 type Hive struct { 80 *HiveParams // settings 81 Overlay // the overlay connectiviy driver 82 Store state.Store // storage interface to save peers across sessions 83 addPeer func(*discover.Node) // server callback to connect to a peer 84 // bookkeeping 85 lock sync.Mutex 86 ticker *time.Ticker 87 } 88 89 // NewHive constructs a new hive 90 // HiveParams: config parameters 91 // Overlay: connectivity driver using a network topology 92 // StateStore: to save peers across sessions 93 func NewHive(params *HiveParams, overlay Overlay, store state.Store) *Hive { 94 return &Hive{ 95 HiveParams: params, 96 Overlay: overlay, 97 Store: store, 98 } 99 } 100 101 // Start stars the hive, receives p2p.Server only at startup 102 // server is used to connect to a peer based on its NodeID or enode URL 103 // these are called on the p2p.Server which runs on the node 104 func (h *Hive) Start(server *p2p.Server) error { 105 log.Info(fmt.Sprintf("%08x hive starting", h.BaseAddr()[:4])) 106 // if state store is specified, load peers to prepopulate the overlay address book 107 if h.Store != nil { 108 log.Info("detected an existing store. trying to load peers") 109 if err := h.loadPeers(); err != nil { 110 log.Error(fmt.Sprintf("%08x hive encoutered an error trying to load peers", h.BaseAddr()[:4])) 111 return err 112 } 113 } 114 // assigns the p2p.Server#AddPeer function to connect to peers 115 h.addPeer = server.AddPeer 116 // ticker to keep the hive alive 117 h.ticker = time.NewTicker(h.KeepAliveInterval) 118 // this loop is doing bootstrapping and maintains a healthy table 119 go h.connect() 120 return nil 121 } 122 123 // Stop terminates the updateloop and saves the peers 124 func (h *Hive) Stop() error { 125 log.Info(fmt.Sprintf("%08x hive stopping, saving peers", h.BaseAddr()[:4])) 126 h.ticker.Stop() 127 if h.Store != nil { 128 if err := h.savePeers(); err != nil { 129 return fmt.Errorf("could not save peers to persistence store: %v", err) 130 } 131 if err := h.Store.Close(); err != nil { 132 return fmt.Errorf("could not close file handle to persistence store: %v", err) 133 } 134 } 135 log.Info(fmt.Sprintf("%08x hive stopped, dropping peers", h.BaseAddr()[:4])) 136 h.EachConn(nil, 255, func(p OverlayConn, _ int, _ bool) bool { 137 log.Info(fmt.Sprintf("%08x dropping peer %08x", h.BaseAddr()[:4], p.Address()[:4])) 138 p.Drop(nil) 139 return true 140 }) 141 142 log.Info(fmt.Sprintf("%08x all peers dropped", h.BaseAddr()[:4])) 143 return nil 144 } 145 146 // connect is a forever loop 147 // at each iteration, ask the overlay driver to suggest the most preferred peer to connect to 148 // as well as advertises saturation depth if needed 149 func (h *Hive) connect() { 150 for range h.ticker.C { 151 152 addr, depth, changed := h.SuggestPeer() 153 if h.Discovery && changed { 154 NotifyDepth(uint8(depth), h) 155 } 156 if addr == nil { 157 continue 158 } 159 160 log.Trace(fmt.Sprintf("%08x hive connect() suggested %08x", h.BaseAddr()[:4], addr.Address()[:4])) 161 under, err := discover.ParseNode(string(addr.(Addr).Under())) 162 if err != nil { 163 log.Warn(fmt.Sprintf("%08x unable to connect to bee %08x: invalid node URL: %v", h.BaseAddr()[:4], addr.Address()[:4], err)) 164 continue 165 } 166 log.Trace(fmt.Sprintf("%08x attempt to connect to bee %08x", h.BaseAddr()[:4], addr.Address()[:4])) 167 h.addPeer(under) 168 } 169 } 170 171 // Run protocol run function 172 func (h *Hive) Run(p *BzzPeer) error { 173 dp := newDiscovery(p, h) 174 depth, changed := h.On(dp) 175 // if we want discovery, advertise change of depth 176 if h.Discovery { 177 if changed { 178 // if depth changed, send to all peers 179 NotifyDepth(depth, h) 180 } else { 181 // otherwise just send depth to new peer 182 dp.NotifyDepth(depth) 183 } 184 } 185 NotifyPeer(p.Off(), h) 186 defer h.Off(dp) 187 return dp.Run(dp.HandleMsg) 188 } 189 190 // NodeInfo function is used by the p2p.server RPC interface to display 191 // protocol specific node information 192 func (h *Hive) NodeInfo() interface{} { 193 return h.String() 194 } 195 196 // PeerInfo function is used by the p2p.server RPC interface to display 197 // protocol specific information any connected peer referred to by their NodeID 198 func (h *Hive) PeerInfo(id discover.NodeID) interface{} { 199 addr := NewAddrFromNodeID(id) 200 return struct { 201 OAddr hexutil.Bytes 202 UAddr hexutil.Bytes 203 }{ 204 OAddr: addr.OAddr, 205 UAddr: addr.UAddr, 206 } 207 } 208 209 // ToAddr returns the serialisable version of u 210 func ToAddr(pa OverlayPeer) *BzzAddr { 211 if addr, ok := pa.(*BzzAddr); ok { 212 return addr 213 } 214 if p, ok := pa.(*discPeer); ok { 215 return p.BzzAddr 216 } 217 return pa.(*BzzPeer).BzzAddr 218 } 219 220 // loadPeers, savePeer implement persistence callback/ 221 func (h *Hive) loadPeers() error { 222 var as []*BzzAddr 223 err := h.Store.Get("peers", &as) 224 if err != nil { 225 if err == state.ErrNotFound { 226 log.Info(fmt.Sprintf("hive %08x: no persisted peers found", h.BaseAddr()[:4])) 227 return nil 228 } 229 return err 230 } 231 log.Info(fmt.Sprintf("hive %08x: peers loaded", h.BaseAddr()[:4])) 232 233 return h.Register(toOverlayAddrs(as...)) 234 } 235 236 // toOverlayAddrs transforms an array of BzzAddr to OverlayAddr 237 func toOverlayAddrs(as ...*BzzAddr) (oas []OverlayAddr) { 238 for _, a := range as { 239 oas = append(oas, OverlayAddr(a)) 240 } 241 return 242 } 243 244 // savePeers, savePeer implement persistence callback/ 245 func (h *Hive) savePeers() error { 246 var peers []*BzzAddr 247 h.Overlay.EachAddr(nil, 256, func(pa OverlayAddr, i int, _ bool) bool { 248 if pa == nil { 249 log.Warn(fmt.Sprintf("empty addr: %v", i)) 250 return true 251 } 252 apa := ToAddr(pa) 253 log.Trace("saving peer", "peer", apa) 254 peers = append(peers, apa) 255 return true 256 }) 257 if err := h.Store.Put("peers", peers); err != nil { 258 return fmt.Errorf("could not save peers: %v", err) 259 } 260 return nil 261 }