All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wavesplatform.api.common.BalanceDistribution.scala Maven / Gradle / Ivy

The newest version!
package com.wavesplatform.api.common

import com.google.common.collect.AbstractIterator
import com.google.common.primitives.{Ints, Longs}
import com.wavesplatform.account.Address
import com.wavesplatform.database.{AddressId, DBResource, Keys}
import com.wavesplatform.transaction.Asset

import scala.annotation.tailrec

object BalanceDistribution {
  class BalanceIterator(
      resource: DBResource,
      globalPrefix: Array[Byte],
      addressId: Array[Byte] => AddressId,
      asset: Asset,
      height: Int,
      private var pendingPortfolios: Map[(Address, Asset), Long]
  ) extends AbstractIterator[(Address, Long)] {
    @inline
    private def stillSameAddress(expected: AddressId): Boolean = resource.fullIterator.isValid && {
      val maybeNext = resource.fullIterator.key()
      maybeNext.startsWith(globalPrefix) && addressId(maybeNext) == expected
    }
    @tailrec
    private def findNextBalance(): Option[(Address, Long)] = {
      if (!resource.fullIterator.isValid) None
      else {
        val key   = resource.fullIterator.key()
        val value = resource.fullIterator.value()
        if (!key.startsWith(globalPrefix)) None
        else {
          val aid           = addressId(key)
          val address       = resource.get(Keys.idToAddress(aid))
          var balance       = Longs.fromByteArray(value)
          var currentHeight = Ints.fromByteArray(key.takeRight(4))

          while (stillSameAddress(aid)) {
            val nextHeight = Ints.fromByteArray(resource.fullIterator.key.takeRight(4))
            if (nextHeight <= height) {
              currentHeight = nextHeight
              balance = Longs.fromByteArray(resource.fullIterator.value())
            }
            resource.fullIterator.next()
          }

          val adjustedBalance = pendingPortfolios.getOrElse((address, asset), balance)
          pendingPortfolios = pendingPortfolios.removed((address, asset))

          if (currentHeight <= height && adjustedBalance > 0)
            Some(address -> adjustedBalance)
          else
            findNextBalance()
        }
      }
    }

    override def computeNext(): (Address, Long) = findNextBalance() match {
      case Some(balance) => balance
      case None =>
        pendingPortfolios.headOption
          .collect { case (key @ (address, `asset`), balance) =>
            pendingPortfolios -= key
            address -> balance
          }
          .getOrElse(endOfData())
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy