github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/stream/delivery.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:43</date> 10 //</624450115179909120> 11 12 13 package stream 14 15 import ( 16 "context" 17 "errors" 18 "fmt" 19 20 "github.com/ethereum/go-ethereum/metrics" 21 "github.com/ethereum/go-ethereum/p2p/enode" 22 "github.com/ethereum/go-ethereum/swarm/log" 23 "github.com/ethereum/go-ethereum/swarm/network" 24 "github.com/ethereum/go-ethereum/swarm/spancontext" 25 "github.com/ethereum/go-ethereum/swarm/storage" 26 opentracing "github.com/opentracing/opentracing-go" 27 ) 28 29 const ( 30 swarmChunkServerStreamName = "RETRIEVE_REQUEST" 31 deliveryCap = 32 32 ) 33 34 var ( 35 processReceivedChunksCount = metrics.NewRegisteredCounter("network.stream.received_chunks.count", nil) 36 handleRetrieveRequestMsgCount = metrics.NewRegisteredCounter("network.stream.handle_retrieve_request_msg.count", nil) 37 retrieveChunkFail = metrics.NewRegisteredCounter("network.stream.retrieve_chunks_fail.count", nil) 38 39 requestFromPeersCount = metrics.NewRegisteredCounter("network.stream.request_from_peers.count", nil) 40 requestFromPeersEachCount = metrics.NewRegisteredCounter("network.stream.request_from_peers_each.count", nil) 41 ) 42 43 type Delivery struct { 44 chunkStore storage.SyncChunkStore 45 kad *network.Kademlia 46 getPeer func(enode.ID) *Peer 47 } 48 49 func NewDelivery(kad *network.Kademlia, chunkStore storage.SyncChunkStore) *Delivery { 50 return &Delivery{ 51 chunkStore: chunkStore, 52 kad: kad, 53 } 54 } 55 56 //swarmchunkserver实现服务器 57 type SwarmChunkServer struct { 58 deliveryC chan []byte 59 batchC chan []byte 60 chunkStore storage.ChunkStore 61 currentLen uint64 62 quit chan struct{} 63 } 64 65 //newswarmchunkserver是swarmchunkserver构造函数 66 func NewSwarmChunkServer(chunkStore storage.ChunkStore) *SwarmChunkServer { 67 s := &SwarmChunkServer{ 68 deliveryC: make(chan []byte, deliveryCap), 69 batchC: make(chan []byte), 70 chunkStore: chunkStore, 71 quit: make(chan struct{}), 72 } 73 go s.processDeliveries() 74 return s 75 } 76 77 //processDeliveries处理已传递的块散列 78 func (s *SwarmChunkServer) processDeliveries() { 79 var hashes []byte 80 var batchC chan []byte 81 for { 82 select { 83 case <-s.quit: 84 return 85 case hash := <-s.deliveryC: 86 hashes = append(hashes, hash...) 87 batchC = s.batchC 88 case batchC <- hashes: 89 hashes = nil 90 batchC = nil 91 } 92 } 93 } 94 95 //对于swarmchunkserver,sessionindex在所有情况下都返回零。 96 func (s *SwarmChunkServer) SessionIndex() (uint64, error) { 97 return 0, nil 98 } 99 100 //设置下一批 101 func (s *SwarmChunkServer) SetNextBatch(_, _ uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error) { 102 select { 103 case hashes = <-s.batchC: 104 case <-s.quit: 105 return 106 } 107 108 from = s.currentLen 109 s.currentLen += uint64(len(hashes)) 110 to = s.currentLen 111 return 112 } 113 114 //需要在流服务器上调用Close 115 func (s *SwarmChunkServer) Close() { 116 close(s.quit) 117 } 118 119 //GetData从数据库存储检索块数据 120 func (s *SwarmChunkServer) GetData(ctx context.Context, key []byte) ([]byte, error) { 121 chunk, err := s.chunkStore.Get(ctx, storage.Address(key)) 122 if err != nil { 123 return nil, err 124 } 125 return chunk.Data(), nil 126 } 127 128 //retrieverequestmsg是块检索请求的协议msg 129 type RetrieveRequestMsg struct { 130 Addr storage.Address 131 SkipCheck bool 132 HopCount uint8 133 } 134 135 func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req *RetrieveRequestMsg) error { 136 log.Trace("received request", "peer", sp.ID(), "hash", req.Addr) 137 handleRetrieveRequestMsgCount.Inc(1) 138 139 var osp opentracing.Span 140 ctx, osp = spancontext.StartSpan( 141 ctx, 142 "retrieve.request") 143 defer osp.Finish() 144 145 s, err := sp.getServer(NewStream(swarmChunkServerStreamName, "", true)) 146 if err != nil { 147 return err 148 } 149 streamer := s.Server.(*SwarmChunkServer) 150 151 var cancel func() 152 //TODO:用这个硬编码超时做点什么,将来可能使用TTL 153 ctx = context.WithValue(ctx, "peer", sp.ID().String()) 154 ctx = context.WithValue(ctx, "hopcount", req.HopCount) 155 ctx, cancel = context.WithTimeout(ctx, network.RequestTimeout) 156 157 go func() { 158 select { 159 case <-ctx.Done(): 160 case <-streamer.quit: 161 } 162 cancel() 163 }() 164 165 go func() { 166 chunk, err := d.chunkStore.Get(ctx, req.Addr) 167 if err != nil { 168 retrieveChunkFail.Inc(1) 169 log.Debug("ChunkStore.Get can not retrieve chunk", "peer", sp.ID().String(), "addr", req.Addr, "hopcount", req.HopCount, "err", err) 170 return 171 } 172 if req.SkipCheck { 173 syncing := false 174 err = sp.Deliver(ctx, chunk, s.priority, syncing) 175 if err != nil { 176 log.Warn("ERROR in handleRetrieveRequestMsg", "err", err) 177 } 178 return 179 } 180 select { 181 case streamer.deliveryC <- chunk.Address()[:]: 182 case <-streamer.quit: 183 } 184 185 }() 186 187 return nil 188 } 189 190 //区块传送总是使用相同的讯息类型…. 191 type ChunkDeliveryMsg struct { 192 Addr storage.Address 193 SData []byte //存储的块数据(包括大小) 194 peer *Peer //设置在handlechunkdeliverymsg中 195 } 196 197 //…但如果交换记帐是用于同步或检索的传递,则需要消除歧义。 198 //根据消息类型决定是否需要解释此消息 199 200 //定义用于检索的块传递(使用记帐) 201 type ChunkDeliveryMsgRetrieval ChunkDeliveryMsg 202 203 //定义用于同步的块传递(无记帐) 204 type ChunkDeliveryMsgSyncing ChunkDeliveryMsg 205 206 //TODO:修复上下文snafu 207 func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *ChunkDeliveryMsg) error { 208 var osp opentracing.Span 209 ctx, osp = spancontext.StartSpan( 210 ctx, 211 "chunk.delivery") 212 defer osp.Finish() 213 214 processReceivedChunksCount.Inc(1) 215 216 go func() { 217 req.peer = sp 218 err := d.chunkStore.Put(ctx, storage.NewChunk(req.Addr, req.SData)) 219 if err != nil { 220 if err == storage.ErrChunkInvalid { 221 //我们删除了这个日志,因为它会破坏日志 222 //TODO:启用此日志行 223 //log.warn(“传递的块无效”,“对等”,sp.id(),“块”,req.addr,) 224 req.peer.Drop(err) 225 } 226 } 227 }() 228 return nil 229 } 230 231 //RequestFromPeers将块检索请求发送到 232 func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) (*enode.ID, chan struct{}, error) { 233 requestFromPeersCount.Inc(1) 234 var sp *Peer 235 spID := req.Source 236 237 if spID != nil { 238 sp = d.getPeer(*spID) 239 if sp == nil { 240 return nil, nil, fmt.Errorf("source peer %v not found", spID.String()) 241 } 242 } else { 243 d.kad.EachConn(req.Addr[:], 255, func(p *network.Peer, po int) bool { 244 id := p.ID() 245 if p.LightNode { 246 //跳过灯光节点 247 return true 248 } 249 if req.SkipPeer(id.String()) { 250 log.Trace("Delivery.RequestFromPeers: skip peer", "peer id", id) 251 return true 252 } 253 sp = d.getPeer(id) 254 if sp == nil { 255 //log.warn(“delivery.requestfrompeers:找不到对等机”,“id”,id) 256 return true 257 } 258 spID = &id 259 return false 260 }) 261 if sp == nil { 262 return nil, nil, errors.New("no peer found") 263 } 264 } 265 266 err := sp.SendPriority(ctx, &RetrieveRequestMsg{ 267 Addr: req.Addr, 268 SkipCheck: req.SkipCheck, 269 HopCount: req.HopCount, 270 }, Top) 271 if err != nil { 272 return nil, nil, err 273 } 274 requestFromPeersEachCount.Inc(1) 275 276 return spID, sp.quit, nil 277 } 278