github.com/cuiweixie/go-ethereum@v1.8.2-0.20180303084001-66cd41af1e38/swarm/network/protocol.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 /* 20 bzz implements the swarm wire protocol [bzz] (sister of eth and shh) 21 the protocol instance is launched on each peer by the network layer if the 22 bzz protocol handler is registered on the p2p server. 23 24 The bzz protocol component speaks the bzz protocol 25 * handle the protocol handshake 26 * register peers in the KΛÐΞMLIΛ table via the hive logistic manager 27 * dispatch to hive for handling the DHT logic 28 * encode and decode requests for storage and retrieval 29 * handle sync protocol messages via the syncer 30 * talks the SWAP payment protocol (swap accounting is done within NetStore) 31 */ 32 33 import ( 34 "errors" 35 "fmt" 36 "net" 37 "strconv" 38 "time" 39 40 "github.com/ethereum/go-ethereum/contracts/chequebook" 41 "github.com/ethereum/go-ethereum/log" 42 "github.com/ethereum/go-ethereum/metrics" 43 "github.com/ethereum/go-ethereum/p2p" 44 bzzswap "github.com/ethereum/go-ethereum/swarm/services/swap" 45 "github.com/ethereum/go-ethereum/swarm/services/swap/swap" 46 "github.com/ethereum/go-ethereum/swarm/storage" 47 ) 48 49 //metrics variables 50 var ( 51 storeRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.storerequest.count", nil) 52 retrieveRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.retrieverequest.count", nil) 53 peersMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.peers.count", nil) 54 syncRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.syncrequest.count", nil) 55 unsyncedKeysMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.unsyncedkeys.count", nil) 56 deliverRequestMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.deliverrequest.count", nil) 57 paymentMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.payment.count", nil) 58 invalidMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.invalid.count", nil) 59 handleStatusMsgCounter = metrics.NewRegisteredCounter("network.protocol.msg.handlestatus.count", nil) 60 ) 61 62 const ( 63 Version = 0 64 ProtocolLength = uint64(8) 65 ProtocolMaxMsgSize = 10 * 1024 * 1024 66 NetworkId = 3 67 ) 68 69 // bzz represents the swarm wire protocol 70 // an instance is running on each peer 71 type bzz struct { 72 storage StorageHandler // handler storage/retrieval related requests coming via the bzz wire protocol 73 hive *Hive // the logistic manager, peerPool, routing service and peer handler 74 dbAccess *DbAccess // access to db storage counter and iterator for syncing 75 requestDb *storage.LDBDatabase // db to persist backlog of deliveries to aid syncing 76 remoteAddr *peerAddr // remote peers address 77 peer *p2p.Peer // the p2p peer object 78 rw p2p.MsgReadWriter // messageReadWriter to send messages to 79 backend chequebook.Backend 80 lastActive time.Time 81 NetworkId uint64 82 83 swap *swap.Swap // swap instance for the peer connection 84 swapParams *bzzswap.SwapParams // swap settings both local and remote 85 swapEnabled bool // flag to enable SWAP (will be set via Caps in handshake) 86 syncEnabled bool // flag to enable SYNC (will be set via Caps in handshake) 87 syncer *syncer // syncer instance for the peer connection 88 syncParams *SyncParams // syncer params 89 syncState *syncState // outgoing syncronisation state (contains reference to remote peers db counter) 90 } 91 92 // interface type for handler of storage/retrieval related requests coming 93 // via the bzz wire protocol 94 // messages: UnsyncedKeys, DeliveryRequest, StoreRequest, RetrieveRequest 95 type StorageHandler interface { 96 HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error 97 HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error 98 HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) 99 HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer) 100 } 101 102 /* 103 main entrypoint, wrappers starting a server that will run the bzz protocol 104 use this constructor to attach the protocol ("class") to server caps 105 This is done by node.Node#Register(func(node.ServiceContext) (Service, error)) 106 Service implements Protocols() which is an array of protocol constructors 107 at node startup the protocols are initialised 108 the Dev p2p layer then calls Run(p *p2p.Peer, rw p2p.MsgReadWriter) error 109 on each peer connection 110 The Run function of the Bzz protocol class creates a bzz instance 111 which will represent the peer for the swarm hive and all peer-aware components 112 */ 113 func Bzz(cloud StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64) (p2p.Protocol, error) { 114 115 // a single global request db is created for all peer connections 116 // this is to persist delivery backlog and aid syncronisation 117 requestDb, err := storage.NewLDBDatabase(sy.RequestDbPath) 118 if err != nil { 119 return p2p.Protocol{}, fmt.Errorf("error setting up request db: %v", err) 120 } 121 if networkId == 0 { 122 networkId = NetworkId 123 } 124 return p2p.Protocol{ 125 Name: "bzz", 126 Version: Version, 127 Length: ProtocolLength, 128 Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error { 129 return run(requestDb, cloud, backend, hive, dbaccess, sp, sy, networkId, p, rw) 130 }, 131 }, nil 132 } 133 134 /* 135 the main protocol loop that 136 * does the handshake by exchanging statusMsg 137 * if peer is valid and accepted, registers with the hive 138 * then enters into a forever loop handling incoming messages 139 * storage and retrieval related queries coming via bzz are dispatched to StorageHandler 140 * peer-related messages are dispatched to the hive 141 * payment related messages are relayed to SWAP service 142 * on disconnect, unregister the peer in the hive (note RemovePeer in the post-disconnect hook) 143 * whenever the loop terminates, the peer will disconnect with Subprotocol error 144 * whenever handlers return an error the loop terminates 145 */ 146 func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook.Backend, hive *Hive, dbaccess *DbAccess, sp *bzzswap.SwapParams, sy *SyncParams, networkId uint64, p *p2p.Peer, rw p2p.MsgReadWriter) (err error) { 147 148 self := &bzz{ 149 storage: depo, 150 backend: backend, 151 hive: hive, 152 dbAccess: dbaccess, 153 requestDb: requestDb, 154 peer: p, 155 rw: rw, 156 swapParams: sp, 157 syncParams: sy, 158 swapEnabled: hive.swapEnabled, 159 syncEnabled: true, 160 NetworkId: networkId, 161 } 162 163 // handle handshake 164 err = self.handleStatus() 165 if err != nil { 166 return err 167 } 168 defer func() { 169 // if the handler loop exits, the peer is disconnecting 170 // deregister the peer in the hive 171 self.hive.removePeer(&peer{bzz: self}) 172 if self.syncer != nil { 173 self.syncer.stop() // quits request db and delivery loops, save requests 174 } 175 if self.swap != nil { 176 self.swap.Stop() // quits chequebox autocash etc 177 } 178 }() 179 180 // the main forever loop that handles incoming requests 181 for { 182 if self.hive.blockRead { 183 log.Warn(fmt.Sprintf("Cannot read network")) 184 time.Sleep(100 * time.Millisecond) 185 continue 186 } 187 err = self.handle() 188 if err != nil { 189 return 190 } 191 } 192 } 193 194 // TODO: may need to implement protocol drop only? don't want to kick off the peer 195 // if they are useful for other protocols 196 func (self *bzz) Drop() { 197 self.peer.Disconnect(p2p.DiscSubprotocolError) 198 } 199 200 // one cycle of the main forever loop that handles and dispatches incoming messages 201 func (self *bzz) handle() error { 202 msg, err := self.rw.ReadMsg() 203 log.Debug(fmt.Sprintf("<- %v", msg)) 204 if err != nil { 205 return err 206 } 207 if msg.Size > ProtocolMaxMsgSize { 208 return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize) 209 } 210 // make sure that the payload has been fully consumed 211 defer msg.Discard() 212 213 switch msg.Code { 214 215 case statusMsg: 216 // no extra status message allowed. The one needed already handled by 217 // handleStatus 218 log.Debug(fmt.Sprintf("Status message: %v", msg)) 219 return errors.New("extra status message") 220 221 case storeRequestMsg: 222 // store requests are dispatched to netStore 223 storeRequestMsgCounter.Inc(1) 224 var req storeRequestMsgData 225 if err := msg.Decode(&req); err != nil { 226 return fmt.Errorf("<- %v: %v", msg, err) 227 } 228 if n := len(req.SData); n < 9 { 229 return fmt.Errorf("<- %v: Data too short (%v)", msg, n) 230 } 231 // last Active time is set only when receiving chunks 232 self.lastActive = time.Now() 233 log.Trace(fmt.Sprintf("incoming store request: %s", req.String())) 234 // swap accounting is done within forwarding 235 self.storage.HandleStoreRequestMsg(&req, &peer{bzz: self}) 236 237 case retrieveRequestMsg: 238 // retrieve Requests are dispatched to netStore 239 retrieveRequestMsgCounter.Inc(1) 240 var req retrieveRequestMsgData 241 if err := msg.Decode(&req); err != nil { 242 return fmt.Errorf("<- %v: %v", msg, err) 243 } 244 req.from = &peer{bzz: self} 245 // if request is lookup and not to be delivered 246 if req.isLookup() { 247 log.Trace(fmt.Sprintf("self lookup for %v: responding with peers only...", req.from)) 248 } else if req.Key == nil { 249 return fmt.Errorf("protocol handler: req.Key == nil || req.Timeout == nil") 250 } else { 251 // swap accounting is done within netStore 252 self.storage.HandleRetrieveRequestMsg(&req, &peer{bzz: self}) 253 } 254 // direct response with peers, TODO: sort this out 255 self.hive.peers(&req) 256 257 case peersMsg: 258 // response to lookups and immediate response to retrieve requests 259 // dispatches new peer data to the hive that adds them to KADDB 260 peersMsgCounter.Inc(1) 261 var req peersMsgData 262 if err := msg.Decode(&req); err != nil { 263 return fmt.Errorf("<- %v: %v", msg, err) 264 } 265 req.from = &peer{bzz: self} 266 log.Trace(fmt.Sprintf("<- peer addresses: %v", req)) 267 self.hive.HandlePeersMsg(&req, &peer{bzz: self}) 268 269 case syncRequestMsg: 270 syncRequestMsgCounter.Inc(1) 271 var req syncRequestMsgData 272 if err := msg.Decode(&req); err != nil { 273 return fmt.Errorf("<- %v: %v", msg, err) 274 } 275 log.Debug(fmt.Sprintf("<- sync request: %v", req)) 276 self.lastActive = time.Now() 277 self.sync(req.SyncState) 278 279 case unsyncedKeysMsg: 280 // coming from parent node offering 281 unsyncedKeysMsgCounter.Inc(1) 282 var req unsyncedKeysMsgData 283 if err := msg.Decode(&req); err != nil { 284 return fmt.Errorf("<- %v: %v", msg, err) 285 } 286 log.Debug(fmt.Sprintf("<- unsynced keys : %s", req.String())) 287 err := self.storage.HandleUnsyncedKeysMsg(&req, &peer{bzz: self}) 288 self.lastActive = time.Now() 289 if err != nil { 290 return fmt.Errorf("<- %v: %v", msg, err) 291 } 292 293 case deliveryRequestMsg: 294 // response to syncKeysMsg hashes filtered not existing in db 295 // also relays the last synced state to the source 296 deliverRequestMsgCounter.Inc(1) 297 var req deliveryRequestMsgData 298 if err := msg.Decode(&req); err != nil { 299 return fmt.Errorf("<-msg %v: %v", msg, err) 300 } 301 log.Debug(fmt.Sprintf("<- delivery request: %s", req.String())) 302 err := self.storage.HandleDeliveryRequestMsg(&req, &peer{bzz: self}) 303 self.lastActive = time.Now() 304 if err != nil { 305 return fmt.Errorf("<- %v: %v", msg, err) 306 } 307 308 case paymentMsg: 309 // swap protocol message for payment, Units paid for, Cheque paid with 310 paymentMsgCounter.Inc(1) 311 if self.swapEnabled { 312 var req paymentMsgData 313 if err := msg.Decode(&req); err != nil { 314 return fmt.Errorf("<- %v: %v", msg, err) 315 } 316 log.Debug(fmt.Sprintf("<- payment: %s", req.String())) 317 self.swap.Receive(int(req.Units), req.Promise) 318 } 319 320 default: 321 // no other message is allowed 322 invalidMsgCounter.Inc(1) 323 return fmt.Errorf("invalid message code: %v", msg.Code) 324 } 325 return nil 326 } 327 328 func (self *bzz) handleStatus() (err error) { 329 330 handshake := &statusMsgData{ 331 Version: uint64(Version), 332 ID: "honey", 333 Addr: self.selfAddr(), 334 NetworkId: self.NetworkId, 335 Swap: &bzzswap.SwapProfile{ 336 Profile: self.swapParams.Profile, 337 PayProfile: self.swapParams.PayProfile, 338 }, 339 } 340 341 err = p2p.Send(self.rw, statusMsg, handshake) 342 if err != nil { 343 return err 344 } 345 346 // read and handle remote status 347 var msg p2p.Msg 348 msg, err = self.rw.ReadMsg() 349 if err != nil { 350 return err 351 } 352 353 if msg.Code != statusMsg { 354 return fmt.Errorf("first msg has code %x (!= %x)", msg.Code, statusMsg) 355 } 356 357 handleStatusMsgCounter.Inc(1) 358 359 if msg.Size > ProtocolMaxMsgSize { 360 return fmt.Errorf("message too long: %v > %v", msg.Size, ProtocolMaxMsgSize) 361 } 362 363 var status statusMsgData 364 if err := msg.Decode(&status); err != nil { 365 return fmt.Errorf("<- %v: %v", msg, err) 366 } 367 368 if status.NetworkId != self.NetworkId { 369 return fmt.Errorf("network id mismatch: %d (!= %d)", status.NetworkId, self.NetworkId) 370 } 371 372 if Version != status.Version { 373 return fmt.Errorf("protocol version mismatch: %d (!= %d)", status.Version, Version) 374 } 375 376 self.remoteAddr = self.peerAddr(status.Addr) 377 log.Trace(fmt.Sprintf("self: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", self.selfAddr(), self.remoteAddr, self.peer.LocalAddr(), status.Addr.IP, self.peer.RemoteAddr())) 378 379 if self.swapEnabled { 380 // set remote profile for accounting 381 self.swap, err = bzzswap.NewSwap(self.swapParams, status.Swap, self.backend, self) 382 if err != nil { 383 return err 384 } 385 } 386 387 log.Info(fmt.Sprintf("Peer %08x is capable (%d/%d)", self.remoteAddr.Addr[:4], status.Version, status.NetworkId)) 388 err = self.hive.addPeer(&peer{bzz: self}) 389 if err != nil { 390 return err 391 } 392 393 // hive sets syncstate so sync should start after node added 394 log.Info(fmt.Sprintf("syncronisation request sent with %v", self.syncState)) 395 self.syncRequest() 396 397 return nil 398 } 399 400 func (self *bzz) sync(state *syncState) error { 401 // syncer setup 402 if self.syncer != nil { 403 return errors.New("sync request can only be sent once") 404 } 405 406 cnt := self.dbAccess.counter() 407 remoteaddr := self.remoteAddr.Addr 408 start, stop := self.hive.kad.KeyRange(remoteaddr) 409 410 // an explicitly received nil syncstate disables syncronisation 411 if state == nil { 412 self.syncEnabled = false 413 log.Warn(fmt.Sprintf("syncronisation disabled for peer %v", self)) 414 state = &syncState{DbSyncState: &storage.DbSyncState{}, Synced: true} 415 } else { 416 state.synced = make(chan bool) 417 state.SessionAt = cnt 418 if storage.IsZeroKey(state.Stop) && state.Synced { 419 state.Start = storage.Key(start[:]) 420 state.Stop = storage.Key(stop[:]) 421 } 422 log.Debug(fmt.Sprintf("syncronisation requested by peer %v at state %v", self, state)) 423 } 424 var err error 425 self.syncer, err = newSyncer( 426 self.requestDb, 427 storage.Key(remoteaddr[:]), 428 self.dbAccess, 429 self.unsyncedKeys, self.store, 430 self.syncParams, state, func() bool { return self.syncEnabled }, 431 ) 432 if err != nil { 433 return nil 434 } 435 log.Trace(fmt.Sprintf("syncer set for peer %v", self)) 436 return nil 437 } 438 439 func (self *bzz) String() string { 440 return self.remoteAddr.String() 441 } 442 443 // repair reported address if IP missing 444 func (self *bzz) peerAddr(base *peerAddr) *peerAddr { 445 if base.IP.IsUnspecified() { 446 host, _, _ := net.SplitHostPort(self.peer.RemoteAddr().String()) 447 base.IP = net.ParseIP(host) 448 } 449 return base 450 } 451 452 // returns self advertised node connection info (listening address w enodes) 453 // IP will get repaired on the other end if missing 454 // or resolved via ID by discovery at dialout 455 func (self *bzz) selfAddr() *peerAddr { 456 id := self.hive.id 457 host, port, _ := net.SplitHostPort(self.hive.listenAddr()) 458 intport, _ := strconv.Atoi(port) 459 addr := &peerAddr{ 460 Addr: self.hive.addr, 461 ID: id[:], 462 IP: net.ParseIP(host), 463 Port: uint16(intport), 464 } 465 return addr 466 } 467 468 // outgoing messages 469 // send retrieveRequestMsg 470 func (self *bzz) retrieve(req *retrieveRequestMsgData) error { 471 return self.send(retrieveRequestMsg, req) 472 } 473 474 // send storeRequestMsg 475 func (self *bzz) store(req *storeRequestMsgData) error { 476 return self.send(storeRequestMsg, req) 477 } 478 479 func (self *bzz) syncRequest() error { 480 req := &syncRequestMsgData{} 481 if self.hive.syncEnabled { 482 log.Debug(fmt.Sprintf("syncronisation request to peer %v at state %v", self, self.syncState)) 483 req.SyncState = self.syncState 484 } 485 if self.syncState == nil { 486 log.Warn(fmt.Sprintf("syncronisation disabled for peer %v at state %v", self, self.syncState)) 487 } 488 return self.send(syncRequestMsg, req) 489 } 490 491 // queue storeRequestMsg in request db 492 func (self *bzz) deliveryRequest(reqs []*syncRequest) error { 493 req := &deliveryRequestMsgData{ 494 Deliver: reqs, 495 } 496 return self.send(deliveryRequestMsg, req) 497 } 498 499 // batch of syncRequests to send off 500 func (self *bzz) unsyncedKeys(reqs []*syncRequest, state *syncState) error { 501 req := &unsyncedKeysMsgData{ 502 Unsynced: reqs, 503 State: state, 504 } 505 return self.send(unsyncedKeysMsg, req) 506 } 507 508 // send paymentMsg 509 func (self *bzz) Pay(units int, promise swap.Promise) { 510 req := &paymentMsgData{uint(units), promise.(*chequebook.Cheque)} 511 self.payment(req) 512 } 513 514 // send paymentMsg 515 func (self *bzz) payment(req *paymentMsgData) error { 516 return self.send(paymentMsg, req) 517 } 518 519 // sends peersMsg 520 func (self *bzz) peers(req *peersMsgData) error { 521 return self.send(peersMsg, req) 522 } 523 524 func (self *bzz) send(msg uint64, data interface{}) error { 525 if self.hive.blockWrite { 526 return fmt.Errorf("network write blocked") 527 } 528 log.Trace(fmt.Sprintf("-> %v: %v (%T) to %v", msg, data, data, self)) 529 err := p2p.Send(self.rw, msg, data) 530 if err != nil { 531 self.Drop() 532 } 533 return err 534 }