@@ -256,7 +256,7 @@ proc downloadInternal(
256256
257257proc requestBlocks * (
258258 self: BlockExcEngine , addresses: seq [BlockAddress ]
259- ): Future [ seq [ ?! Block ]] {. async : (raises: [ CancelledError ]).} =
259+ ): SafeAsyncIter [ Block ] =
260260 var handles: seq [BlockHandle ]
261261 # Adds all blocks to pendingBlocks before calling the first downloadInternal. This will
262262 # ensure that we don't send incomplete want lists.
@@ -267,20 +267,27 @@ proc requestBlocks*(
267267 for address in addresses:
268268 self.trackedFutures.track (self.downloadInternal (address))
269269
270- # TODO : we can reduce latency and improve download times
271- # by returning blocks out of order as futures complete.
272- var blocks: seq [?! Block ]
273- for handle in handles:
274- try :
275- blocks.add (success await handle)
276- except CancelledError as err:
277- warn " Block request cancelled" , addresses, err = err.msg
278- raise err
279- except CatchableError as err:
280- error " Error getting blocks from exchange engine" , addresses, err = err.msg
281- blocks.add (Block .failure err)
270+ var completed: int = 0
271+
272+ proc isFinished (): bool =
273+ completed == handles.len
274+
275+ proc genNext (): Future [?! Block ] {.async : (raises: [CancelledError ]).} =
276+ # Be it success or failure, we're completing this future.
277+ let value =
278+ try :
279+ success await handles[completed]
280+ except CancelledError as err:
281+ warn " Block request cancelled" , addresses, err = err.msg
282+ raise err
283+ except CatchableError as err:
284+ error " Error getting blocks from exchange engine" , addresses, err = err.msg
285+ failure err
282286
283- return blocks
287+ inc (completed)
288+ return value
289+
290+ return SafeAsyncIter [Block ].new (genNext, isFinished)
284291
285292proc requestBlock * (
286293 self: BlockExcEngine , address: BlockAddress
@@ -368,28 +375,42 @@ proc cancelBlocks(
368375 # # Tells neighboring peers that we're no longer interested in a block.
369376 # #
370377
378+ let addrSet = toHashSet (addrs)
379+ var pendingCancellations: Table [PeerId , HashSet [BlockAddress ]]
380+
371381 if self.peers.len == 0 :
372382 return
373383
374384 trace " Sending block request cancellations to peers" ,
375385 addrs, peers = self.peers.peerIds
376386
377- proc processPeer (peerCtx: BlockExcPeerCtx ): Future [BlockExcPeerCtx ] {.async .} =
387+ proc processPeer (
388+ entry: tuple [peerId: PeerId , addresses: HashSet [BlockAddress ]]
389+ ): Future [PeerId ] {.async : (raises: [CancelledError ]).} =
378390 await self.network.request.sendWantCancellations (
379- peer = peerCtx.id , addresses = addrs. filterIt (it in peerCtx)
391+ peer = entry.peerId , addresses = entry.addresses.toSeq
380392 )
381393
382- return peerCtx
394+ return entry.peerId
383395
384396 try :
385- let (succeededFuts, failedFuts) = await allFinishedFailed [BlockExcPeerCtx ](
386- toSeq (self.peers.peers.values).filterIt (it.peerHave.anyIt (it in addrs)).map (
387- processPeer
388- )
397+ # Does the peer have any of the blocks we're canceling?
398+ for peerCtx in self.peers.peers.values:
399+ let intersection = peerCtx.peerHave.intersection (addrSet)
400+ if intersection.len > 0 :
401+ pendingCancellations[peerCtx.id] = intersection
402+
403+ # If so, dispatches cancellations.
404+ # FIXME: we're still spamming peers - the fact that the peer has the block does
405+ # not mean we've requested it.
406+ let (succeededFuts, failedFuts) = await allFinishedFailed [PeerId ](
407+ toSeq (pendingCancellations.pairs).map (processPeer)
389408 )
390409
391- (await allFinished (succeededFuts)).mapIt (it.read).apply do (peerCtx: BlockExcPeerCtx ):
392- peerCtx.cleanPresence (addrs)
410+ (await allFinished (succeededFuts)).mapIt (it.read).apply do (peerId: PeerId ):
411+ let ctx = self.peers.get (peerId)
412+ if not ctx.isNil:
413+ ctx.cleanPresence (addrs)
393414
394415 if failedFuts.len > 0 :
395416 warn " Failed to send block request cancellations to peers" , peers = failedFuts.len
@@ -539,6 +560,8 @@ proc wantListHandler*(
539560 price = @ (self.pricing.get (Pricing (price: 0 .u256)).price.toBytesBE)
540561
541562 if e.cancel:
563+ # This is sort of expected if we sent the block to the peer, as we have removed
564+ # it from the peer's wantlist ourselves.
542565 trace " Received cancelation for untracked block, skipping" ,
543566 address = e.address
544567 continue
0 commit comments