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