diff --git a/node/src/main/scala/com/wavesplatform/api/common/lease/LeaseByAddressIterator.scala b/node/src/main/scala/com/wavesplatform/api/common/lease/LeaseByAddressIterator.scala index 4f235cf90a..6f18da0c21 100644 --- a/node/src/main/scala/com/wavesplatform/api/common/lease/LeaseByAddressIterator.scala +++ b/node/src/main/scala/com/wavesplatform/api/common/lease/LeaseByAddressIterator.scala @@ -6,27 +6,19 @@ import com.wavesplatform.database import com.wavesplatform.database.{AddressId, DBResource, Keys} import com.wavesplatform.state.LeaseDetails -import scala.collection.mutable - private class LeaseByAddressIterator(resource: DBResource, addressId: AddressId) extends AbstractIterator[Seq[(ByteStr, LeaseDetails)]] { private val seqNr = resource.get(Keys.addressLeaseSeqNr(addressId)) resource.withSafePrefixIterator(_.seekForPrev(Keys.addressLeaseSeq(addressId, seqNr).keyBytes))() final override def computeNext(): Seq[(ByteStr, LeaseDetails)] = resource.withSafePrefixIterator { iterator => - val buffer = mutable.Map[ByteStr, LeaseDetails]() - while (iterator.isValid) { - for { - id <- database.readLeaseIdSeq(iterator.value()) + if (iterator.isValid) { + val details = for { + id <- database.readLeaseIdSeq(iterator.value()) details <- database.loadLease(resource, id) if details.isActive - } buffer.update(id, details) + } yield (id, details) iterator.prev() - } - if (buffer.nonEmpty) - buffer.toSeq - else - endOfData() - }( - endOfData() - ) + details + } else endOfData() + }(endOfData()) } diff --git a/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala b/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala index c44609d60b..fc9fb46d4f 100644 --- a/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala +++ b/node/src/main/scala/com/wavesplatform/database/RocksDBWriter.scala @@ -557,8 +557,11 @@ class RocksDBWriter( address <- Seq(details.recipientAddress, details.sender.toAddress) addressId = this.addressIdWithFallback(address, newAddresses) } yield (addressId, leaseId) - val leaseIdsByAddressId = addressIdWithLeaseIds.groupMap { case (addressId, _) => (addressId, Keys.addressLeaseSeqNr(addressId)) }(_._2) - rw.multiGetInts(leaseIdsByAddressId.keys.map(_._2).toSeq) + val leaseIdsByAddressId = addressIdWithLeaseIds + .groupMap { case (addressId, _) => (addressId, Keys.addressLeaseSeqNr(addressId)) }(_._2) + .toSeq + + rw.multiGetInts(leaseIdsByAddressId.map(_._1._2)) .zip(leaseIdsByAddressId) .foreach { case (prevSeqNr, ((addressId, leaseSeqKey), leaseIds)) => val nextSeqNr = prevSeqNr.getOrElse(0) + 1 diff --git a/node/src/test/scala/com/wavesplatform/http/LeaseRouteSpec.scala b/node/src/test/scala/com/wavesplatform/http/LeaseRouteSpec.scala index 103bf5564f..38cb5a1921 100644 --- a/node/src/test/scala/com/wavesplatform/http/LeaseRouteSpec.scala +++ b/node/src/test/scala/com/wavesplatform/http/LeaseRouteSpec.scala @@ -484,6 +484,34 @@ class LeaseRouteSpec extends RouteSpec("/leasing") with OptionValues with RestAP checkForInvoke(EthTxGenerator.generateEthInvoke(invoker.toEthKeyPair, dApp1.toAddress, "foo", Seq.empty, Seq.empty)) } + "multiple leases in the same block" in { + val sender = TxHelpers.signer(240) + val leases1 = Seq.tabulate(10)(i => TxHelpers.lease(sender, TxHelpers.address(241 + i))) + val leases2 = Seq.tabulate(10)(i => TxHelpers.lease(sender, TxHelpers.address(251 + i))) + val leases3 = Seq.tabulate(10)(i => TxHelpers.lease(sender, TxHelpers.address(261 + i))) + val leases4 = Seq.tabulate(10)(i => TxHelpers.lease(sender, TxHelpers.address(271 + i))) + + domain.appendBlock(TxHelpers.transfer(richAccount, sender.toAddress, 10_000.waves)) + domain.appendBlock(leases1*) + domain.appendBlock(leases2*) + domain.appendBlock(leases3*) + domain.appendBlock(leases4*) + domain.appendBlock() + + import monix.execution.Scheduler.Implicits.global + val leases = domain.accountsApi.activeLeases(sender.toAddress).toListL.runSyncUnsafe(15.seconds) + leases.size shouldEqual 40 + + Get(routePath(s"/active/${sender.toAddress}")) ~> route ~> check { + responseAs[Seq[JsObject]].map(v => (v \ "id").as[ByteStr]) should contain theSameElementsAs ( + leases4.map(_.id()) ++ + leases3.map(_.id()) ++ + leases2.map(_.id()) ++ + leases1.map(_.id()) + ) + } + } + routePath("/info") in { val lease = TxHelpers.lease()