github.com/pslzym/go-ethereum@v1.8.17-0.20180926104442-4b6824e07b1b/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/ethereum/go-ethereum/metrics" 25 "github.com/ethereum/go-ethereum/swarm/log" 26 bv "github.com/ethereum/go-ethereum/swarm/network/bitvector" 27 "github.com/ethereum/go-ethereum/swarm/spancontext" 28 "github.com/ethereum/go-ethereum/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 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, "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 199 hashes := req.Hashes 200 lenHashes := len(hashes) 201 if lenHashes%HashSize != 0 { 202 return fmt.Errorf("error invalid hashes length (len: %v)", lenHashes) 203 } 204 205 want, err := bv.New(lenHashes / HashSize) 206 if err != nil { 207 return fmt.Errorf("error initiaising bitvector of length %v: %v", lenHashes/HashSize, err) 208 } 209 210 ctr := 0 211 errC := make(chan error) 212 ctx, cancel := context.WithTimeout(ctx, syncBatchTimeout) 213 214 ctx = context.WithValue(ctx, "source", p.ID().String()) 215 for i := 0; i < lenHashes; i += HashSize { 216 hash := hashes[i : i+HashSize] 217 218 if wait := c.NeedData(ctx, hash); wait != nil { 219 ctr++ 220 want.Set(i/HashSize, true) 221 // create request and wait until the chunk data arrives and is stored 222 go func(w func(context.Context) error) { 223 select { 224 case errC <- w(ctx): 225 case <-ctx.Done(): 226 } 227 }(wait) 228 } 229 } 230 231 go func() { 232 defer cancel() 233 for i := 0; i < ctr; i++ { 234 select { 235 case err := <-errC: 236 if err != nil { 237 log.Debug("client.handleOfferedHashesMsg() error waiting for chunk, dropping peer", "peer", p.ID(), "err", err) 238 p.Drop(err) 239 return 240 } 241 case <-ctx.Done(): 242 log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) 243 return 244 case <-c.quit: 245 log.Debug("client.handleOfferedHashesMsg() quit") 246 return 247 } 248 } 249 select { 250 case c.next <- c.batchDone(p, req, hashes): 251 case <-c.quit: 252 log.Debug("client.handleOfferedHashesMsg() quit") 253 case <-ctx.Done(): 254 log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) 255 } 256 }() 257 // only send wantedKeysMsg if all missing chunks of the previous batch arrived 258 // except 259 if c.stream.Live { 260 c.sessionAt = req.From 261 } 262 from, to := c.nextBatch(req.To + 1) 263 log.Trace("set next batch", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To, "addr", p.streamer.addr) 264 if from == to { 265 return nil 266 } 267 268 msg := &WantedHashesMsg{ 269 Stream: req.Stream, 270 Want: want.Bytes(), 271 From: from, 272 To: to, 273 } 274 go func() { 275 log.Trace("sending want batch", "peer", p.ID(), "stream", msg.Stream, "from", msg.From, "to", msg.To) 276 select { 277 case err := <-c.next: 278 if err != nil { 279 log.Warn("c.next error dropping peer", "err", err) 280 p.Drop(err) 281 return 282 } 283 case <-c.quit: 284 log.Debug("client.handleOfferedHashesMsg() quit") 285 return 286 case <-ctx.Done(): 287 log.Debug("client.handleOfferedHashesMsg() context done", "ctx.Err()", ctx.Err()) 288 return 289 } 290 log.Trace("sending want batch", "peer", p.ID(), "stream", msg.Stream, "from", msg.From, "to", msg.To) 291 err := p.SendPriority(ctx, msg, c.priority) 292 if err != nil { 293 log.Warn("SendPriority error", "err", err) 294 } 295 }() 296 return nil 297 } 298 299 // WantedHashesMsg is the protocol msg data for signaling which hashes 300 // offered in OfferedHashesMsg downstream peer actually wants sent over 301 type WantedHashesMsg struct { 302 Stream Stream 303 Want []byte // bitvector indicating which keys of the batch needed 304 From, To uint64 // next interval offset - empty if not to be continued 305 } 306 307 // String pretty prints WantedHashesMsg 308 func (m WantedHashesMsg) String() string { 309 return fmt.Sprintf("Stream '%v', Want: %x, Next: [%v-%v]", m.Stream, m.Want, m.From, m.To) 310 } 311 312 // handleWantedHashesMsg protocol msg handler 313 // * sends the next batch of unsynced keys 314 // * sends the actual data chunks as per WantedHashesMsg 315 func (p *Peer) handleWantedHashesMsg(ctx context.Context, req *WantedHashesMsg) error { 316 metrics.GetOrRegisterCounter("peer.handlewantedhashesmsg", nil).Inc(1) 317 318 log.Trace("received wanted batch", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To) 319 s, err := p.getServer(req.Stream) 320 if err != nil { 321 return err 322 } 323 hashes := s.currentBatch 324 // launch in go routine since GetBatch blocks until new hashes arrive 325 go func() { 326 if err := p.SendOfferedHashes(s, req.From, req.To); err != nil { 327 log.Warn("SendOfferedHashes error", "err", err) 328 } 329 }() 330 // go p.SendOfferedHashes(s, req.From, req.To) 331 l := len(hashes) / HashSize 332 333 log.Trace("wanted batch length", "peer", p.ID(), "stream", req.Stream, "from", req.From, "to", req.To, "lenhashes", len(hashes), "l", l) 334 want, err := bv.NewFromBytes(req.Want, l) 335 if err != nil { 336 return fmt.Errorf("error initiaising bitvector of length %v: %v", l, err) 337 } 338 for i := 0; i < l; i++ { 339 if want.Get(i) { 340 metrics.GetOrRegisterCounter("peer.handlewantedhashesmsg.actualget", nil).Inc(1) 341 342 hash := hashes[i*HashSize : (i+1)*HashSize] 343 data, err := s.GetData(ctx, hash) 344 if err != nil { 345 return fmt.Errorf("handleWantedHashesMsg get data %x: %v", hash, err) 346 } 347 chunk := storage.NewChunk(hash, data) 348 if err := p.Deliver(ctx, chunk, s.priority); err != nil { 349 return err 350 } 351 } 352 } 353 return nil 354 } 355 356 // Handover represents a statement that the upstream peer hands over the stream section 357 type Handover struct { 358 Stream Stream // name of stream 359 Start, End uint64 // index of hashes 360 Root []byte // Root hash for indexed segment inclusion proofs 361 } 362 363 // HandoverProof represents a signed statement that the upstream peer handed over the stream section 364 type HandoverProof struct { 365 Sig []byte // Sign(Hash(Serialisation(Handover))) 366 *Handover 367 } 368 369 // Takeover represents a statement that downstream peer took over (stored all data) 370 // handed over 371 type Takeover Handover 372 373 // TakeoverProof represents a signed statement that the downstream peer took over 374 // the stream section 375 type TakeoverProof struct { 376 Sig []byte // Sign(Hash(Serialisation(Takeover))) 377 *Takeover 378 } 379 380 // TakeoverProofMsg is the protocol msg sent by downstream peer 381 type TakeoverProofMsg TakeoverProof 382 383 // String pretty prints TakeoverProofMsg 384 func (m TakeoverProofMsg) String() string { 385 return fmt.Sprintf("Stream: '%v' [%v-%v], Root: %x, Sig: %x", m.Stream, m.Start, m.End, m.Root, m.Sig) 386 } 387 388 func (p *Peer) handleTakeoverProofMsg(ctx context.Context, req *TakeoverProofMsg) error { 389 _, err := p.getServer(req.Stream) 390 // store the strongest takeoverproof for the stream in streamer 391 return err 392 }