2024 10 21 Replace Future.sequence() usage with Future.traverse() (#5732)

* Use more Future.traverse()

* More Future.traverse()
This commit is contained in:
Chris Stewart 2024-10-22 16:57:23 -05:00 committed by GitHub
parent 528ceae9d4
commit 65e67287f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 53 additions and 63 deletions

View File

@ -223,9 +223,10 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit
from: BlockHeaderDb, from: BlockHeaderDb,
to: BlockHeaderDb to: BlockHeaderDb
): Future[Vector[BlockHeaderDb]] = { ): Future[Vector[BlockHeaderDb]] = {
val range = from.height.to(to.height).toVector
val headerFs = val headerFs =
from.height.to(to.height).map(height => getHeaderAtHeight(height)) Future.traverse(range)(height => getHeaderAtHeight(height))
Future.sequence(headerFs).map(_.toVector) headerFs
} }
private def getHeaderAtHeight(height: Int): Future[BlockHeaderDb] = private def getHeaderAtHeight(height: Int): Future[BlockHeaderDb] =

View File

@ -332,7 +332,7 @@ trait BlockchainRpc extends ChainApi { self: Client =>
val allHeights = startHeight.to(endHeight) val allHeights = startHeight.to(endHeight)
def f(range: Vector[Int]): Future[Vector[FilterResponse]] = { def f(range: Vector[Int]): Future[Vector[FilterResponse]] = {
val filterFs = range.map { height => val filterFs = Future.traverse(range) { height =>
for { for {
hash <- getBlockHash(height) hash <- getBlockHash(height)
filter <- getBlockFilter(hash, FilterType.Basic) filter <- getBlockFilter(hash, FilterType.Basic)
@ -340,7 +340,7 @@ trait BlockchainRpc extends ChainApi { self: Client =>
FilterResponse(filter.filter, hash, height) FilterResponse(filter.filter, hash, height)
} }
} }
Future.sequence(filterFs) filterFs
} }
FutureUtil.batchAndSyncExecute( FutureUtil.batchAndSyncExecute(

View File

@ -952,10 +952,9 @@ class ChainHandler(
case Some(blockHeight) => case Some(blockHeight) =>
for { for {
tips <- getBestChainTips() tips <- getBestChainTips()
getNAncestorsFs = tips.map { tip => ancestorChains <- Future.traverse(tips) { tip =>
blockHeaderDAO.getNAncestors(tip.hashBE, tip.height - blockHeight) blockHeaderDAO.getNAncestors(tip.hashBE, tip.height - blockHeight)
} }
ancestorChains <- Future.sequence(getNAncestorsFs)
} yield { } yield {
val confs = ancestorChains.flatMap { chain => val confs = ancestorChains.flatMap { chain =>
if (chain.last.hashBE == blockHash) { if (chain.last.hashBE == blockHash) {

View File

@ -162,14 +162,11 @@ abstract class FilterSync extends ChainVerificationLogger {
)(implicit ec: ExecutionContext): Future[ChainApi] = { )(implicit ec: ExecutionContext): Future[ChainApi] = {
// now that we have headers that are missing filters, let's fetch the filters // now that we have headers that are missing filters, let's fetch the filters
val fetchNested = missingHeaders.map { b => val fetchFiltersF: Future[Vector[(BlockHeaderDb, FilterWithHeaderHash)]] =
val filterF = getFilterFunc(b.blockHeader) Future.traverse(missingHeaders) { b =>
filterF.map(f => (b, f)) val filterF = getFilterFunc(b.blockHeader)
} filterF.map(f => (b, f))
}
val fetchFiltersF: Future[Vector[(BlockHeaderDb, FilterWithHeaderHash)]] = {
Future.sequence(fetchNested)
}
// now let's build filter headers // now let's build filter headers
val blockFiltersAggF: Future[Vector[BlockFilterAggregated]] = { val blockFiltersAggF: Future[Vector[BlockFilterAggregated]] = {

View File

@ -400,17 +400,19 @@ case class BlockHeaderDAO()(implicit
val chainTipsF = getForkedChainTips val chainTipsF = getForkedChainTips
val bestTipF = getBestChainTips val bestTipF = getBestChainTips
val staleChainsF = chainTipsF.flatMap { tips => val staleChainsF = chainTipsF.flatMap { tips =>
val nestedFuture: Vector[Future[Option[Blockchain]]] = tips.map { tip => Future
getBlockchainFrom(tip) .traverse(tips) { tip =>
} getBlockchainFrom(tip)
Future.sequence(nestedFuture).map(_.flatten) }
.map(_.flatten)
} }
val bestChainsF = bestTipF.flatMap { tips => val bestChainsF = bestTipF.flatMap { tips =>
val nestedFuture: Vector[Future[Option[Blockchain]]] = tips.map { tip => Future
getBlockchainFrom(tip) .traverse(tips) { tip =>
} getBlockchainFrom(tip)
Future.sequence(nestedFuture).map(_.flatten) }
.map(_.flatten)
} }
for { for {

View File

@ -67,7 +67,7 @@ trait BitcoinSCryptoAsyncTest
.toVector .toVector
.flatten .flatten
val testRunsF = Future.sequence(samples.map(func)) val testRunsF = Future.traverse(samples)(func)
checkRunResults(testRunsF) checkRunResults(testRunsF)
} }
@ -84,7 +84,7 @@ trait BitcoinSCryptoAsyncTest
(a, b) (a, b)
} }
val testRunsF = Future.sequence(samples.map(x => func(x._1, x._2))) val testRunsF = Future.traverse(samples)(x => func(x._1, x._2))
checkRunResults(testRunsF) checkRunResults(testRunsF)
} }

View File

@ -80,12 +80,12 @@ trait LndRouterClient { self: LndRpcClient =>
routeHints: Vector[LnRoute] routeHints: Vector[LnRoute]
): Future[Vector[Route]] = { ): Future[Vector[Route]] = {
queryRoutes(amount, node, routeHints).map(_.routes).flatMap { routes => queryRoutes(amount, node, routeHints).map(_.routes).flatMap { routes =>
val fs = routes.toVector.map { route => val fs = Future.traverse(routes.toVector) { route =>
val fakeHash = CryptoUtil.sha256(ECPrivateKey.freshPrivateKey.bytes) val fakeHash = CryptoUtil.sha256(ECPrivateKey.freshPrivateKey.bytes)
sendToRoute(fakeHash, route).map(t => (route, t)) sendToRoute(fakeHash, route).map(t => (route, t))
} }
Future.sequence(fs).map { results => fs.map { results =>
results results
.filter( .filter(
_._2.failure.exists(_.code == INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS) _._2.failure.exists(_.code == INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS)

View File

@ -75,9 +75,8 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair {
val node = nodeConnectedWithBitcoind.node val node = nodeConnectedWithBitcoind.node
def peerManager = node.peerManager def peerManager = node.peerManager
def peers = peerManager.peers def peers = peerManager.peers
val ourPeersF: Future[Vector[Peer]] = Future.sequence( val ourPeersF: Future[Vector[Peer]] = Future.traverse(
nodeConnectedWithBitcoind.bitcoinds.map(NodeTestUtil.getBitcoindPeer) nodeConnectedWithBitcoind.bitcoinds)(NodeTestUtil.getBitcoindPeer)
)
def has2Peers: Future[Unit] = def has2Peers: Future[Unit] =
AsyncUtil.retryUntilSatisfied( AsyncUtil.retryUntilSatisfied(
@ -89,10 +88,10 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair {
assert(ours.map(peers.contains(_)).forall(_ == true)) assert(ours.map(peers.contains(_)).forall(_ == true))
} }
def allConnected: Future[Assertion] = for { def allConnected: Future[Assertion] = for {
conns <- Future.sequence(peers.map(peerManager.isConnected)) conns <- Future.traverse(peers)(peerManager.isConnected)
} yield assert(conns.forall(_ == true)) } yield assert(conns.forall(_ == true))
def allInitialized: Future[Assertion] = for { def allInitialized: Future[Assertion] = for {
inits <- Future.sequence(peers.map(peerManager.isInitialized)) inits <- Future.traverse(peers)(peerManager.isInitialized)
} yield assert(inits.forall(_ == true)) } yield assert(inits.forall(_ == true))
for { for {
@ -144,9 +143,8 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair {
for { for {
_ <- assertConnAndInit _ <- assertConnAndInit
ourPeers <- Future.sequence( ourPeers <- Future.traverse(nodeConnectedWithBitcoind.bitcoinds)(
nodeConnectedWithBitcoind.bitcoinds.map(NodeTestUtil.getBitcoindPeer) NodeTestUtil.getBitcoindPeer)
)
peerDbs <- PeerDAO()(node.nodeAppConfig, executionContext).findAll() peerDbs <- PeerDAO()(node.nodeAppConfig, executionContext).findAll()
} yield { } yield {

View File

@ -27,8 +27,7 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor {
lazy val bitcoinPeersF: Future[Vector[Peer]] = { lazy val bitcoinPeersF: Future[Vector[Peer]] = {
bitcoindsF.flatMap { bitcoinds => bitcoindsF.flatMap { bitcoinds =>
val peersF = bitcoinds.map(NodeTestUtil.getBitcoindPeer) Future.traverse(bitcoinds)(NodeTestUtil.getBitcoindPeer)
Future.sequence(peersF)
} }
} }

View File

@ -1152,7 +1152,7 @@ trait DLCTest {
constructAndSetupDLC(contractParams) constructAndSetupDLC(contractParams)
.flatMap { .flatMap {
case (dlcOffer, offerSetup, dlcAccept, acceptSetup, outcomes) => case (dlcOffer, offerSetup, dlcAccept, acceptSetup, outcomes) =>
val testFs = outcomeIndices.map { val testFs = Future.traverse(outcomeIndices) {
case (contractIndex, outcomeIndex) => case (contractIndex, outcomeIndex) =>
executeForOutcome( executeForOutcome(
outcomeIndex = outcomeIndex, outcomeIndex = outcomeIndex,
@ -1164,8 +1164,7 @@ trait DLCTest {
contractIndex = contractIndex contractIndex = contractIndex
) )
} }
testFs.map(_ => succeed)
Future.sequence(testFs).map(_ => succeed)
} }
} }

View File

@ -659,14 +659,12 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
def sendPayments(c1: EclairApi, c2: EclairApi, numPayments: Int = 5)(implicit def sendPayments(c1: EclairApi, c2: EclairApi, numPayments: Int = 5)(implicit
ec: ExecutionContext ec: ExecutionContext
): Future[Vector[PaymentId]] = { ): Future[Vector[PaymentId]] = {
val payments = (1 to numPayments) val range = 1.to(numPayments).toVector
.map(MilliSatoshis(_)) val amounts = range.map(MilliSatoshis(_))
.map(sats => val resultF =
Future.traverse(amounts)(sats =>
c1.createInvoice(s"this is a note for $sats") c1.createInvoice(s"this is a note for $sats")
.flatMap(invoice => c2.payInvoice(invoice, sats))) .flatMap(invoice => c2.payInvoice(invoice, sats)))
val resultF = Future.sequence(payments).map(_.toVector)
resultF.onComplete { resultF.onComplete {
case Success(_) => case Success(_) =>
case Failure(_) => case Failure(_) =>
@ -832,7 +830,7 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
def shutdown()(implicit ec: ExecutionContext): Future[Unit] = def shutdown()(implicit ec: ExecutionContext): Future[Unit] =
for { for {
_ <- Future.sequence(networkEclairNodes.map(_.stop())) _ <- Future.traverse(networkEclairNodes)(_.stop())
_ <- testEclairNode.stop() _ <- testEclairNode.stop()
_ <- bitcoind.stop() _ <- bitcoind.stop()
} yield () } yield ()
@ -882,13 +880,10 @@ trait EclairRpcTestUtil extends BitcoinSLogger {
) )
) )
) )
_ <- Future.sequence(networkEclairNodes.map(_.start())) _ <- Future.traverse(networkEclairNodes)(_.start())
_ <- Future.sequence( _ <- Future.traverse(networkEclairNodes)(awaitEclairInSync(_, bitcoind))
networkEclairNodes.map(awaitEclairInSync(_, bitcoind)) _ <- Future.traverse(networkEclairNodes)(
) connectLNNodes(_, testEclairNode))
_ <- Future.sequence(
networkEclairNodes.map(connectLNNodes(_, testEclairNode))
)
channelIds <- networkEclairNodes.foldLeft( channelIds <- networkEclairNodes.foldLeft(
Future.successful(Vector.empty[FundedChannelId]) Future.successful(Vector.empty[FundedChannelId])
) { (accF, node) => ) { (accF, node) =>

View File

@ -488,10 +488,10 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
hashes <- clients.head.generateToAddress(blocks, address) hashes <- clients.head.generateToAddress(blocks, address)
_ <- { _ <- {
val pairs = ListUtil.uniquePairs(clients) val pairs = ListUtil.uniquePairs(clients)
val syncFuts = pairs.map { case (first, second) => val syncFuts = Future.traverse(pairs) { case (first, second) =>
awaitSynced(first, second) awaitSynced(first, second)
} }
Future.sequence(syncFuts) syncFuts
} }
} yield hashes } yield hashes
} }
@ -635,10 +635,10 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
pairs: Vector[(BitcoindRpcClient, BitcoindRpcClient)] pairs: Vector[(BitcoindRpcClient, BitcoindRpcClient)]
)(implicit system: ActorSystem): Future[Unit] = { )(implicit system: ActorSystem): Future[Unit] = {
import system.dispatcher import system.dispatcher
val futures = pairs.map { case (first, second) => val futures = Future.traverse(pairs) { case (first, second) =>
BitcoindRpcTestUtil.awaitSynced(first, second) BitcoindRpcTestUtil.awaitSynced(first, second)
} }
Future.sequence(futures).map(_ => ()) futures.map(_ => ())
} }
/** Connects and waits non-blockingly until all the provided pairs of clients /** Connects and waits non-blockingly until all the provided pairs of clients
@ -649,18 +649,18 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
)(implicit system: ActorSystem): Future[Unit] = { )(implicit system: ActorSystem): Future[Unit] = {
import system.dispatcher import system.dispatcher
val addNodesF: Future[Vector[Unit]] = { val addNodesF: Future[Vector[Unit]] = {
val addedF = pairs.map { case (first, second) => val addedF = Future.traverse(pairs) { case (first, second) =>
first.addNode(second.getDaemon.uri, AddNodeArgument.Add) first.addNode(second.getDaemon.uri, AddNodeArgument.Add)
} }
Future.sequence(addedF) addedF
} }
val connectedPairsF = addNodesF.flatMap { _ => val connectedPairsF = addNodesF.flatMap { _ =>
val futures = pairs.map { case (first, second) => val futures = Future.traverse(pairs) { case (first, second) =>
BitcoindRpcTestUtil BitcoindRpcTestUtil
.awaitConnection(first, second, interval = 1.second) .awaitConnection(first, second, interval = 1.second)
} }
Future.sequence(futures) futures
} }
connectedPairsF.map(_ => ()) connectedPairsF.map(_ => ())
@ -1025,7 +1025,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
def deleteNodePair(client1: BitcoindRpcClient, client2: BitcoindRpcClient)( def deleteNodePair(client1: BitcoindRpcClient, client2: BitcoindRpcClient)(
implicit executionContext: ExecutionContext implicit executionContext: ExecutionContext
): Future[Unit] = { ): Future[Unit] = {
val stopsF = List(client1, client2).map { client => val stopsF = Future.traverse(List(client1, client2)) { client =>
implicit val sys = client.system implicit val sys = client.system
for { for {
_ <- client.stop() _ <- client.stop()
@ -1033,7 +1033,7 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger {
_ <- removeDataDirectory(client) _ <- removeDataDirectory(client)
} yield () } yield ()
} }
Future.sequence(stopsF).map(_ => ()) stopsF.map(_ => ())
} }
/** Checks whether the provided client has seen the given block hash /** Checks whether the provided client has seen the given block hash