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