From b5202dbd51212684db2892561698431d937a5cd4 Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Fri, 1 Mar 2024 21:24:28 +1100 Subject: [PATCH 01/12] Update BlockchainApiRoute.scala --- .../http/api/BlockchainApiRoute.scala | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala index 0be225d035..8da9f2c26f 100644 --- a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala @@ -242,37 +242,45 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting validateAndGetBoxesByAddress(address, offset, limit) } - private def getBoxesByAddressUnspent(addr: ErgoAddress, offset: Int, limit: Int, sortDir: Direction, unconfirmed: Boolean): Future[Seq[IndexedErgoBox]] = + private def getBoxesByAddressUnspent(addr: ErgoAddress, offset: Int, limit: Int, sortDir: Direction, unconfirmed: Boolean, excludeMempoolSpent: Boolean): Future[Seq[IndexedErgoBox]] = getHistoryWithMempool.map { case (history, mempool) => - getAddress(addr)(history) - .getOrElse(IndexedErgoAddress(hashErgoTree(addr.script))) - .retrieveUtxos(history, mempool, offset, limit, sortDir, unconfirmed) + val addressUtxos = getAddress(addr)(history) + .getOrElse(IndexedErgoAddress(hashErgoTree(addr.script))) + .retrieveUtxos(history, mempool, offset, limit, sortDir, unconfirmed) + if (excludeMempoolSpent) { + // If excluding boxes spent in mempool, filter out those boxes + val spentBoxesIdsInMempool = mempool.spentInputs.toSet + addressUtxos.filterNot(box => spentBoxesIdsInMempool.contains(box.id)) + } else { + addressUtxos } + } private def validateAndGetBoxesByAddressUnspent(address: ErgoAddress, offset: Int, limit: Int, dir: Direction, - unconfirmed: Boolean): Route = { + unconfirmed: Boolean, + excludeMempoolSpent: Boolean): Route = { if (limit > MaxItems) { BadRequest(s"No more than $MaxItems boxes can be requested") } else if (dir == SortDirection.INVALID) { BadRequest("Invalid parameter for sort direction, valid values are \"ASC\" and \"DESC\"") } else { - ApiResponse(getBoxesByAddressUnspent(address, offset, limit, dir, unconfirmed)) + ApiResponse(getBoxesByAddressUnspent(address, offset, limit, dir, unconfirmed, excludeMempoolSpent)) } } private def getBoxesByAddressUnspentR: Route = (post & pathPrefix("box" / "unspent" / "byAddress") & ergoAddress & paging & sortDir & unconfirmed) { - (address, offset, limit, dir, unconfirmed) => - validateAndGetBoxesByAddressUnspent(address, offset, limit, dir, unconfirmed) + (address, offset, limit, dir, unconfirmed, excludeMempoolSpent) => + validateAndGetBoxesByAddressUnspent(address, offset, limit, dir, unconfirmed, excludeMempoolSpent) } private def getBoxesByAddressUnspentGetRoute: Route = (pathPrefix("box" / "unspent" / "byAddress") & get & addressPass & paging & sortDir & unconfirmed) { - (address, offset, limit, dir, unconfirmed) => - validateAndGetBoxesByAddressUnspent(address, offset, limit, dir, unconfirmed) + (address, offset, limit, dir, unconfirmed, excludeMempoolSpent) => + validateAndGetBoxesByAddressUnspent(address, offset, limit, dir, unconfirmed, excludeMempoolSpent) } private def getBoxRange(offset: Int, limit: Int): Future[Seq[ModifierId]] = From ed8acdfb65acaea266ea88ff4312222e42d41b25 Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Fri, 1 Mar 2024 21:26:26 +1100 Subject: [PATCH 02/12] Update openapi.yaml --- src/main/resources/api/openapi.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/resources/api/openapi.yaml b/src/main/resources/api/openapi.yaml index 24062ad56d..914cc3815f 100644 --- a/src/main/resources/api/openapi.yaml +++ b/src/main/resources/api/openapi.yaml @@ -6413,6 +6413,13 @@ paths: schema: type: boolean default: false + - in: query + name: exludeMempoolSpent + required: false + description: if true exclude spent inputs from mempool + schema: + type: boolean + default: false responses: '200': description: unspent boxes associated with wanted address From 2669890837c900326c9bfe2cad103994cc4dc0eb Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Fri, 1 Mar 2024 21:26:39 +1100 Subject: [PATCH 03/12] Update openapi-ai.yaml --- src/main/resources/api/openapi-ai.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/resources/api/openapi-ai.yaml b/src/main/resources/api/openapi-ai.yaml index 1e562ff0f5..41696443fe 100644 --- a/src/main/resources/api/openapi-ai.yaml +++ b/src/main/resources/api/openapi-ai.yaml @@ -1390,6 +1390,13 @@ paths: schema: type: string default: desc + - in: query + name: exludeMempoolSpent + required: false + description: if true exclude spent inputs from mempool + schema: + type: boolean + default: false responses: '200': description: unspent boxes associated with wanted address @@ -1479,4 +1486,4 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ApiError' \ No newline at end of file + $ref: '#/components/schemas/ApiError' From f211055c128c3e61e3be5634a18c37528ca0367d Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Fri, 15 Mar 2024 23:05:29 +1100 Subject: [PATCH 04/12] Fix typo for param name --- src/main/resources/api/openapi-ai.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/api/openapi-ai.yaml b/src/main/resources/api/openapi-ai.yaml index 41696443fe..61dd8bb9b2 100644 --- a/src/main/resources/api/openapi-ai.yaml +++ b/src/main/resources/api/openapi-ai.yaml @@ -1391,7 +1391,7 @@ paths: type: string default: desc - in: query - name: exludeMempoolSpent + name: excludeMempoolSpent required: false description: if true exclude spent inputs from mempool schema: From e1f82868a5a78d814aeec95f51fde41a86e80dfb Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Fri, 15 Mar 2024 23:05:52 +1100 Subject: [PATCH 05/12] Fix typo for param name --- src/main/resources/api/openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/api/openapi.yaml b/src/main/resources/api/openapi.yaml index 914cc3815f..5384aa8124 100644 --- a/src/main/resources/api/openapi.yaml +++ b/src/main/resources/api/openapi.yaml @@ -6414,7 +6414,7 @@ paths: type: boolean default: false - in: query - name: exludeMempoolSpent + name: excludeMempoolSpent required: false description: if true exclude spent inputs from mempool schema: From 1aef809c372b645253615a3c78b46e6045f5c62c Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Wed, 20 Mar 2024 01:28:42 +1100 Subject: [PATCH 06/12] Add recursive search for utxos --- .../http/api/BlockchainApiRoute.scala | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala index 8da9f2c26f..09ed609c0f 100644 --- a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala @@ -256,6 +256,43 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting } } + private def getBoxesByAddressUnspent( + addr: ErgoAddress, + offset: Int, + limit: Int, + sortDir: Direction, + unconfirmed: Boolean, + excludeMempoolSpent: Boolean +): Future[Seq[IndexedErgoBox]] = { + + def fetchAndFilter(limit: Int, accumulated: Seq[IndexedErgoBox] = Seq.empty): Future[Seq[IndexedErgoBox]] = { + getHistoryWithMempool.flatMap { case (history, mempool) => + val addressUtxos = getAddress(addr)(history) + .getOrElse(IndexedErgoAddress(hashErgoTree(addr.script))) + .retrieveUtxos(history, mempool, offset + accumulated.length, limit, sortDir, unconfirmed) + + val newUtxos = if (excludeMempoolSpent) { + val spentBoxesIdsInMempool = mempool.spentInputs.toSet + addressUtxos.filterNot(box => spentBoxesIdsInMempool.contains(box.id)) + } else { + addressUtxos + } + + val updatedAccumulated = accumulated ++ newUtxos + // If reached limit OR we have obtained the maximumm available UTXOS (returned amount < limit), return successful. + if (updatedAccumulated.length >= originalLimit || addressUtxos.length < limit) { + Future.successful(updatedAccumulated.take(originalLimit)) // Just to ensure that no more than limit is taken + } else { + val maxLimit = 200; + val newLimit = Math.min(limit * 2, maxLimit); // Prevents limit becoming too large + fetchAndFilter(newLimit, updatedAccumulated) + } + } + } + val originalLimit = limit + fetchAndFilter(originalLimit) +} + private def validateAndGetBoxesByAddressUnspent(address: ErgoAddress, offset: Int, limit: Int, From 7ee480c4ae78a4e32095fdcb9f725dd7bb679754 Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Wed, 20 Mar 2024 01:30:49 +1100 Subject: [PATCH 07/12] Remove old implementation --- .../ergoplatform/http/api/BlockchainApiRoute.scala | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala index 09ed609c0f..727d7e902b 100644 --- a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala @@ -242,20 +242,6 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting validateAndGetBoxesByAddress(address, offset, limit) } - private def getBoxesByAddressUnspent(addr: ErgoAddress, offset: Int, limit: Int, sortDir: Direction, unconfirmed: Boolean, excludeMempoolSpent: Boolean): Future[Seq[IndexedErgoBox]] = - getHistoryWithMempool.map { case (history, mempool) => - val addressUtxos = getAddress(addr)(history) - .getOrElse(IndexedErgoAddress(hashErgoTree(addr.script))) - .retrieveUtxos(history, mempool, offset, limit, sortDir, unconfirmed) - if (excludeMempoolSpent) { - // If excluding boxes spent in mempool, filter out those boxes - val spentBoxesIdsInMempool = mempool.spentInputs.toSet - addressUtxos.filterNot(box => spentBoxesIdsInMempool.contains(box.id)) - } else { - addressUtxos - } - } - private def getBoxesByAddressUnspent( addr: ErgoAddress, offset: Int, From d97effd08666e004afce6dd8105ae474cb0b964f Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Mon, 25 Mar 2024 18:33:30 +1100 Subject: [PATCH 08/12] Attempt fix for bad signatures --- .../ergoplatform/http/api/BlockchainApiRoute.scala | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala index 727d7e902b..aacd62fc7e 100644 --- a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala @@ -295,17 +295,20 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting } private def getBoxesByAddressUnspentR: Route = - (post & pathPrefix("box" / "unspent" / "byAddress") & ergoAddress & paging & sortDir & unconfirmed) { - (address, offset, limit, dir, unconfirmed, excludeMempoolSpent) => + (post & pathPrefix("box" / "unspent" / "byAddress") & ergoAddress & paging & sortDir & unconfirmed & parameter('excludeMempoolSpent.as[Boolean].?)) { + (address, offset, limit, dir, unconfirmed, excludeMempoolSpentOption) => + val excludeMempoolSpent = excludeMempoolSpentOption.getOrElse(false) validateAndGetBoxesByAddressUnspent(address, offset, limit, dir, unconfirmed, excludeMempoolSpent) } private def getBoxesByAddressUnspentGetRoute: Route = - (pathPrefix("box" / "unspent" / "byAddress") & get & addressPass & paging & sortDir & unconfirmed) { - (address, offset, limit, dir, unconfirmed, excludeMempoolSpent) => + (pathPrefix("box" / "unspent" / "byAddress") & get & addressPass & paging & sortDir & unconfirmed & parameter('excludeMempoolSpent.as[Boolean].?)) { + (address, offset, limit, dir, unconfirmed, excludeMempoolSpentOption) => + val excludeMempoolSpent = excludeMempoolSpentOption.getOrElse(false) validateAndGetBoxesByAddressUnspent(address, offset, limit, dir, unconfirmed, excludeMempoolSpent) } + private def getBoxRange(offset: Int, limit: Int): Future[Seq[ModifierId]] = getHistory.map { history => val base: Long = getIndex(GlobalBoxIndexKey, history).getLong - offset From 6783dc53f58ba8a07a622b5df29153059b40c8d0 Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Mon, 25 Mar 2024 18:46:38 +1100 Subject: [PATCH 09/12] Attempt to fix type mismatch --- .../org/ergoplatform/http/api/BlockchainApiRoute.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala index aacd62fc7e..0bfbca0f03 100644 --- a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala @@ -257,13 +257,13 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting .getOrElse(IndexedErgoAddress(hashErgoTree(addr.script))) .retrieveUtxos(history, mempool, offset + accumulated.length, limit, sortDir, unconfirmed) + val spentBoxesIdsInMempool: Set[Array[Byte]] = mempool.spentInputs.map(idToBytes).toSet val newUtxos = if (excludeMempoolSpent) { - val spentBoxesIdsInMempool = mempool.spentInputs.toSet - addressUtxos.filterNot(box => spentBoxesIdsInMempool.contains(box.id)) + addressUtxos.filterNot(box => spentBoxesIdsInMempool.contains(idToBytes(box.id))) } else { addressUtxos - } - + } + val updatedAccumulated = accumulated ++ newUtxos // If reached limit OR we have obtained the maximumm available UTXOS (returned amount < limit), return successful. if (updatedAccumulated.length >= originalLimit || addressUtxos.length < limit) { From 3f9cb459a8e13b9085e33bf4e20be1c9a497e4c9 Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Thu, 28 Mar 2024 16:08:41 +1100 Subject: [PATCH 10/12] Fix filtering of spent boxes in mempool using ModifierId --- .../org/ergoplatform/http/api/BlockchainApiRoute.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala index 0bfbca0f03..48a87bfe6f 100644 --- a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala @@ -251,15 +251,17 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting excludeMempoolSpent: Boolean ): Future[Seq[IndexedErgoBox]] = { + val originalLimit = limit + def fetchAndFilter(limit: Int, accumulated: Seq[IndexedErgoBox] = Seq.empty): Future[Seq[IndexedErgoBox]] = { getHistoryWithMempool.flatMap { case (history, mempool) => val addressUtxos = getAddress(addr)(history) .getOrElse(IndexedErgoAddress(hashErgoTree(addr.script))) .retrieveUtxos(history, mempool, offset + accumulated.length, limit, sortDir, unconfirmed) - val spentBoxesIdsInMempool: Set[Array[Byte]] = mempool.spentInputs.map(idToBytes).toSet + val spentBoxesIdsInMempool: Set[ModifierId] = mempool.spentInputs.map(bytesToId).toSet val newUtxos = if (excludeMempoolSpent) { - addressUtxos.filterNot(box => spentBoxesIdsInMempool.contains(idToBytes(box.id))) + addressUtxos.filterNot(box => spentBoxesIdsInMempool.contains(box.id)) } else { addressUtxos } @@ -271,11 +273,11 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting } else { val maxLimit = 200; val newLimit = Math.min(limit * 2, maxLimit); // Prevents limit becoming too large - fetchAndFilter(newLimit, updatedAccumulated) + fetchAndFilter(newLimit, updatedAccumulated) } } } - val originalLimit = limit + fetchAndFilter(originalLimit) } From beac0a223fb3445ffba3195a66f8242cbc729c80 Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Fri, 19 Apr 2024 22:28:23 +1000 Subject: [PATCH 11/12] Pass excludeMempoolSpent into retrieveUtxos --- .../http/api/BlockchainApiRoute.scala | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala index 48a87bfe6f..8ef0b5f035 100644 --- a/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/BlockchainApiRoute.scala @@ -255,24 +255,18 @@ case class BlockchainApiRoute(readersHolder: ActorRef, ergoSettings: ErgoSetting def fetchAndFilter(limit: Int, accumulated: Seq[IndexedErgoBox] = Seq.empty): Future[Seq[IndexedErgoBox]] = { getHistoryWithMempool.flatMap { case (history, mempool) => + val spentBoxesIdsInMempool = if (excludeMempoolSpent) mempool.spentInputs.map(bytesToId).toSet else Set.empty[ModifierId] + val addressUtxos = getAddress(addr)(history) .getOrElse(IndexedErgoAddress(hashErgoTree(addr.script))) - .retrieveUtxos(history, mempool, offset + accumulated.length, limit, sortDir, unconfirmed) + .retrieveUtxos(history, mempool, offset + accumulated.length, limit, sortDir, unconfirmed, spentBoxesIdsInMempool) - val spentBoxesIdsInMempool: Set[ModifierId] = mempool.spentInputs.map(bytesToId).toSet - val newUtxos = if (excludeMempoolSpent) { - addressUtxos.filterNot(box => spentBoxesIdsInMempool.contains(box.id)) - } else { - addressUtxos - } - - val updatedAccumulated = accumulated ++ newUtxos - // If reached limit OR we have obtained the maximumm available UTXOS (returned amount < limit), return successful. + val updatedAccumulated = accumulated ++ addressUtxos if (updatedAccumulated.length >= originalLimit || addressUtxos.length < limit) { - Future.successful(updatedAccumulated.take(originalLimit)) // Just to ensure that no more than limit is taken + Future.successful(updatedAccumulated.take(originalLimit)) } else { - val maxLimit = 200; - val newLimit = Math.min(limit * 2, maxLimit); // Prevents limit becoming too large + val maxLimit = 200 + val newLimit = Math.min(limit * 2, maxLimit) fetchAndFilter(newLimit, updatedAccumulated) } } From 3a2ab2bf2634fd11faf6b9926cb4f41c5019c6e0 Mon Sep 17 00:00:00 2001 From: anon-yum2 <161828021+anon-yum2@users.noreply.github.com> Date: Fri, 19 Apr 2024 22:29:29 +1000 Subject: [PATCH 12/12] Add overloaded retrieveUtxos --- .../nodeView/history/extra/Segment.scala | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/main/scala/org/ergoplatform/nodeView/history/extra/Segment.scala b/src/main/scala/org/ergoplatform/nodeView/history/extra/Segment.scala index c45a5c9595..c42c5c1ec3 100644 --- a/src/main/scala/org/ergoplatform/nodeView/history/extra/Segment.scala +++ b/src/main/scala/org/ergoplatform/nodeView/history/extra/Segment.scala @@ -287,6 +287,60 @@ abstract class Segment[T <: Segment[_] : ClassTag](val parentId: ModifierId, confirmedBoxes } + + /** + * Overloaded retrieveUtxos for mempool filtering + * Get a range of the boxes associated with the parent that are NOT spent + * + * @param history - history to use + * @param mempool - mempool to use, if unconfirmed is true + * @param offset - items to skip from the start + * @param limit - items to retrieve + * @param sortDir - whether to start retreival from newest box ([[DESC]]) or oldest box ([[ASC]]) + * @param unconfirmed - whether to include unconfirmed boxes + * @param spentBoxesIdsInMempool - Set of box IDs that are spent in the mempool (to be excluded if necessary) + * @return array of unspent boxes + */ + def retrieveUtxos(history: ErgoHistoryReader, + mempool: ErgoMemPoolReader, + offset: Int, + limit: Int, + sortDir: Direction, + unconfirmed: Boolean, + spentBoxesIdsInMempool: Set[ModifierId]): Seq[IndexedErgoBox] = { + val data: ArrayBuffer[IndexedErgoBox] = ArrayBuffer.empty[IndexedErgoBox] + val confirmedBoxes: Seq[IndexedErgoBox] = sortDir match { + case DESC => + data ++= boxes.filter(_ > 0).map(n => NumericBoxIndex.getBoxByNumber(history, n).get).filterNot(box => spentBoxesIdsInMempool.contains(box.id)) + var segment: Int = boxSegmentCount + while(data.length < (limit + offset) && segment > 0) { + segment -= 1 + history.typedExtraIndexById[T](idMod(boxSegmentId(parentId, segment))).get.boxes + .filter(_ > 0).map(n => NumericBoxIndex.getBoxByNumber(history, n).get).filterNot(box => spentBoxesIdsInMempool.contains(box.id)) ++=: data + } + data.reverse.slice(offset, offset + limit) + case ASC => + var segment: Int = 0 + while(data.length < (limit + offset) && segment < boxSegmentCount) { + data ++= history.typedExtraIndexById[T](idMod(boxSegmentId(parentId, segment))).get.boxes + .filter(_ > 0).map(n => NumericBoxIndex.getBoxByNumber(history, n).get).filterNot(box => spentBoxesIdsInMempool.contains(box.id)) + segment += 1 + } + if (data.length < (limit + offset)) + data ++= boxes.filter(_ > 0).map(n => NumericBoxIndex.getBoxByNumber(history, n).get).filterNot(box => spentBoxesIdsInMempool.contains(box.id)) + data.slice(offset, offset + limit) + } + if(unconfirmed) { + val mempoolBoxes = filterMempool(mempool.getAll.flatMap(_.transaction.outputs)) + val unconfirmedBoxes = mempoolBoxes.map(new IndexedErgoBox(0, None, None, _, 0)).filterNot(box => spentBoxesIdsInMempool.contains(box.id)) + sortDir match { + case DESC => unconfirmedBoxes ++ confirmedBoxes + case ASC => confirmedBoxes ++ unconfirmedBoxes + } + } else + confirmedBoxes + } + /** * Logic for [[Segment.rollback]] *