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