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