github.com/Ethersocial/go-esn@v0.3.7/swarm/network/stream/messages.go (about) 1 // Copyright 2018 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 stream 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 "github.com/ethersocial/go-esn/metrics" 25 "github.com/ethersocial/go-esn/swarm/log" 26 bv "github.com/ethersocial/go-esn/swarm/network/bitvector" 27 "github.com/ethersocial/go-esn/swarm/spancontext" 28 "github.com/ethersocial/go-esn/swarm/storage" 29 "github.com/opentracing/opentracing-go" 30 ) 31 32 var syncBatchTimeout = 30 * time.Second 33 34 // Stream defines a unique stream identifier. 35 type Stream struct { 36 // Name is used for Client and Server functions identification. 37 Name string 38 // Key is the name of specific stream data. 39 Key string 40 // Live defines whether the stream delivers only new data 41 // for the specific stream. 42 Live bool 43 } 44 45 func NewStream(name string, key string, live bool) Stream { 46 return Stream{ 47 Name: name, 48 Key: key, 49 Live: live, 50 } 51 } 52 53 // String return a stream id based on all Stream fields. 54 func (s Stream) String() string { 55 t := "h" 56 if s.Live { 57 t = "l" 58 } 59 return fmt.Sprintf("%s|%s|%s", s.Name, s.Key, t) 60 } 61 62 // SubcribeMsg is the protocol msg for requesting a stream(section) 63 type SubscribeMsg struct { 64 Stream Stream 65 History *Range `rlp:"nil"` 66 Priority uint8 // delivered on priority channel 67 } 68 69 // RequestSubscriptionMsg is the protocol msg for a node to request subscription to a 70 // specific stream 71 type RequestSubscriptionMsg struct { 72 Stream Stream 73 History *Range `rlp:"nil"` 74 Priority uint8 // delivered on priority channel 75 } 76 77 func (p *Peer) handleRequestSubscription(ctx context.Context, req *RequestSubscriptionMsg) (err error) { 78 log.Debug(fmt.Sprintf("handleRequestSubscription: streamer %s to subscribe to %s with stream %s", p.streamer.addr, p.ID(), req.Stream)) 79 return p.streamer.Subscribe(p.ID(), req.Stream, req.History, req.Priority) 80 } 81 82 func (p *Peer) handleSubscribeMsg(ctx context.Context, req *SubscribeMsg) (err error) { 83 metrics.GetOrRegisterCounter("peer.handlesubscribemsg", nil).Inc(1) 84 85 defer func() { 86 if err != nil { 87 // The error will be sent as a subscribe error message 88 // and will not be returned as it will prevent any new message 89 // exchange between peers over p2p. Instead, error will be returned 90 // only if there is one from sending subscribe error message. 91 err = p.Send(context.TODO(), SubscribeErrorMsg{ 92 Error: err.Error(), 93 }) 94 } 95 }() 96 97 log.Debug("received subscription", "from", p.streamer.addr, "peer", p.ID(), "stream", req.Stream, "history", req.History) 98 99 f, err := p.streamer.GetServerFunc(req.Stream.Name) 100 if err != nil { 101 return err 102 } 103 104 s, err := f(p, req.Stream.Key, req.Stream.Live) 105 if err != nil { 106 return err 107 } 108 os, err := p.setServer(req.Stream, s, req.Priority) 109 if err != nil { 110 return err 111 } 112 113 var from uint64 114 var to uint64 115 if !req.Stream.Live && req.History != nil { 116 from = req.History.From 117 to = req.History.To 118 } 119 120 go func() { 121 if err := p.SendOfferedHashes(os, from, to); err != nil { 122 log.Warn("SendOfferedHashes error", "peer", p.ID().TerminalString(), "err", err) 123 } 124 }() 125 126 if req.Stream.Live && req.History != nil { 127 // subscribe to the history stream 128 s, err := f(p, req.Stream.Key, false) 129 if err != nil { 130 return err 131 } 132 133 os, err := p.setServer(getHistoryStream(req.Stream), s, getHistoryPriority(req.Priority)) 134 if err != nil { 135 return err 136 } 137 go func() { 138 if err := p.SendOfferedHashes(os, req.History.From, req.History.To); err != nil { 139 log.Warn("SendOfferedHashes error", "peer", p.ID().TerminalString(), "err", err) 140 } 141 }() 142 } 143 144 return nil 145 } 146 147 type SubscribeErrorMsg struct { 148 Error string 149 } 150 151 func (p *Peer) handleSubscribeErrorMsg(req *SubscribeErrorMsg) (err error) { 152 return fmt.Errorf("subscribe to peer %s: %v", p.ID(), req.Error) 153 } 154 155 type UnsubscribeMsg struct { 156 Stream Stream 157 } 158 159 func (p *Peer) handleUnsubscribeMsg(req *UnsubscribeMsg) error { 160 return p.removeServer(req.Stream) 161 } 162 163 type QuitMsg struct { 164 Stream Stream 165 } 166 167 func (p *Peer) handleQuitMsg(req *QuitMsg) error { 168 return p.removeClient(req.Stream) 169 } 170 171 // OfferedHashesMsg is the protocol msg for offering to hand over a 172 // stream section 173 type OfferedHashesMsg struct { 174 Stream Stream // name of Stream 175 From, To uint64 // peer and db-specific entry count 176 Hashes []byte // stream of hashes (128) 177 *HandoverProof // HandoverProof 178 } 179 180 // String pretty prints OfferedHashesMsg 181 func (m OfferedHashesMsg) String() string { 182 return fmt.Sprintf("Stream '%v' [%v-%v] (%v)", m.Stream, m.From, m.To, len(m.Hashes)/HashSize) 183 } 184 185 // handleOfferedHashesMsg protocol msg handler calls the incoming streamer interface 186 // Filter method 187 func (p *Peer) handleOfferedHashesMsg(ctx context.Context, req *OfferedHashesMsg) error { 188 metrics.GetOrRegisterCounter("peer.handleofferedhashes", nil).Inc(1) 189 190 var sp opentracing.Span 191 ctx, sp = spancontext.StartSpan( 192 ctx, 193 "handle.offered.hashes") 194 defer sp.Finish() 195 196 c, _, err := p.getOrSetClient(req.Stream, req.From, req.To) 197 if err != nil { 198 return err 199 } 200 201 hashes := req.Hashes 202 lenHashes := len(hashes) 203 if lenHashes%HashSize != 0 { 204 return fmt.Errorf("error invalid hashes length (len: %v)", lenHashes) 205 } 206 207 want, err := bv.New(lenHashes / HashSize) 208 if err != nil { 209 return fmt.Errorf("error initiaising bitvector of length %v: %v", lenHashes/HashSize, err) 210 } 211 212 ctr := 0 213 errC := make(chan error) 214 ctx, cancel := context.WithTimeout(ctx, syncBatchTimeout) 215 216 ctx = context.WithValue(ctx, "source", p.ID().String()) 217 for i := 0; i < lenHashes; i += HashSize { 218 hash := hashes[i : i+HashSize] 219 220 if wait := c.NeedData(ctx, hash); wait != nil { 221 ctr++ 222 want.Set(i/HashSize, true) 223 // create request and wait until the chunk data arrives and is stored 224 go func(w func(context.Context) error) { 225 select { 226 case errC <- w(ctx): 227 case <-ctx.Done(): 228 } 229 }(wait) 230 } 231 } 232 233 go func() { 234 defer cancel() 235 for i := 0; i < ctr; i++ { 236 select { 237 case err := <-errC: 238 if err != nil { 239 log.Debug("client.handleOfferedHashesMsg() error waiting for chunk, dropping peer", "peer", p.ID(), "err", err) 240 p.Drop(err) 241 return 242 } 243 case <-ctx.Done(): 244 log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) 245 return 246 case <-c.quit: 247 log.Debug("client.handleOfferedHashesMsg() quit") 248 return 249 } 250 } 251 select { 252 case c.next <- c.batchDone(p, req, hashes): 253 case <-c.quit: 254 log.Debug("client.handleOfferedHashesMsg() quit") 255 case <-ctx.Done(): 256 log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) 257 } 258 }() 259 // only send wantedKeysMsg if all missing chunks of the previous batch arrived 260 // except 261 if c.stream.Live { 262 c.sessionAt = req.From 263 } 264 from, to := c.nextBatch(req.To + 1) 265 log.Trace("set next batch", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To, "addr", p.streamer.addr) 266 if from == to { 267 return nil 268 } 269 270 msg := &WantedHashesMsg{ 271 Stream: req.Stream, 272 Want: want.Bytes(), 273 From: from, 274 To: to, 275 } 276 go func() { 277 log.Trace("sending want batch", "peer", p.ID(), "stream", msg.Stream, "from", msg.From, "to", msg.To) 278 select { 279 case err := <-c.next: 280 if err != nil { 281 log.Warn("c.next error dropping peer", "err", err) 282 p.Drop(err) 283 return 284 } 285 case <-c.quit: 286 log.Debug("client.handleOfferedHashesMsg() quit") 287 return 288 case <-ctx.Done(): 289 log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) 290 return 291 } 292 log.Trace("sending want batch", "peer", p.ID(), "stream", msg.Stream, "from", msg.From, "to", msg.To) 293 err := p.SendPriority(ctx, msg, c.priority) 294 if err != nil { 295 log.Warn("SendPriority error", "err", err) 296 } 297 }() 298 return nil 299 } 300 301 // WantedHashesMsg is the protocol msg data for signaling which hashes 302 // offered in OfferedHashesMsg downstream peer actually wants sent over 303 type WantedHashesMsg struct { 304 Stream Stream 305 Want []byte // bitvector indicating which keys of the batch needed 306 From, To uint64 // next interval offset - empty if not to be continued 307 } 308 309 // String pretty prints WantedHashesMsg 310 func (m WantedHashesMsg) String() string { 311 return fmt.Sprintf("Stream '%v', Want: %x, Next: [%v-%v]", m.Stream, m.Want, m.From, m.To) 312 } 313 314 // handleWantedHashesMsg protocol msg handler 315 // * sends the next batch of unsynced keys 316 // * sends the actual data chunks as per WantedHashesMsg 317 func (p *Peer) handleWantedHashesMsg(ctx context.Context, req *WantedHashesMsg) error { 318 metrics.GetOrRegisterCounter("peer.handlewantedhashesmsg", nil).Inc(1) 319 320 log.Trace("received wanted batch", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To) 321 s, err := p.getServer(req.Stream) 322 if err != nil { 323 return err 324 } 325 hashes := s.currentBatch 326 // launch in go routine since GetBatch blocks until new hashes arrive 327 go func() { 328 if err := p.SendOfferedHashes(s, req.From, req.To); err != nil { 329 log.Warn("SendOfferedHashes error", "err", err) 330 } 331 }() 332 // go p.SendOfferedHashes(s, req.From, req.To) 333 l := len(hashes) / HashSize 334 335 log.Trace("wanted batch length", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To, "lenhashes", len(hashes), "l", l) 336 want, err := bv.NewFromBytes(req.Want, l) 337 if err != nil { 338 return fmt.Errorf("error initiaising bitvector of length %v: %v", l, err) 339 } 340 for i := 0; i < l; i++ { 341 if want.Get(i) { 342 metrics.GetOrRegisterCounter("peer.handlewantedhashesmsg.actualget", nil).Inc(1) 343 344 hash := hashes[i*HashSize : (i+1)*HashSize] 345 data, err := s.GetData(ctx, hash) 346 if err != nil { 347 return fmt.Errorf("handleWantedHashesMsg get data %x: %v", hash, err) 348 } 349 chunk := storage.NewChunk(hash, data) 350 if err := p.Deliver(ctx, chunk, s.priority); err != nil { 351 return err 352 } 353 } 354 } 355 return nil 356 } 357 358 // Handover represents a statement that the upstream peer hands over the stream section 359 type Handover struct { 360 Stream Stream // name of stream 361 Start, End uint64 // index of hashes 362 Root []byte // Root hash for indexed segment inclusion proofs 363 } 364 365 // HandoverProof represents a signed statement that the upstream peer handed over the stream section 366 type HandoverProof struct { 367 Sig []byte // Sign(Hash(Serialisation(Handover))) 368 *Handover 369 } 370 371 // Takeover represents a statement that downstream peer took over (stored all data) 372 // handed over 373 type Takeover Handover 374 375 // TakeoverProof represents a signed statement that the downstream peer took over 376 // the stream section 377 type TakeoverProof struct { 378 Sig []byte // Sign(Hash(Serialisation(Takeover))) 379 *Takeover 380 } 381 382 // TakeoverProofMsg is the protocol msg sent by downstream peer 383 type TakeoverProofMsg TakeoverProof 384 385 // String pretty prints TakeoverProofMsg 386 func (m TakeoverProofMsg) String() string { 387 return fmt.Sprintf("Stream: '%v' [%v-%v], Root: %x, Sig: %x", m.Stream, m.Start, m.End, m.Root, m.Sig) 388 } 389 390 func (p *Peer) handleTakeoverProofMsg(ctx context.Context, req *TakeoverProofMsg) error { 391 _, err := p.getServer(req.Stream) 392 // store the strongest takeoverproof for the stream in streamer 393 return err 394 }