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