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

com.wavesplatform.settings.BlockchainSettings.scala Maven / Gradle / Ivy

The newest version!
package com.wavesplatform.settings

import cats.syntax.either.*
import cats.syntax.traverse.*
import com.typesafe.config.Config
import com.wavesplatform.account.Address
import com.wavesplatform.common.state.ByteStr
import net.ceedubs.ficus.Ficus.*
import net.ceedubs.ficus.readers.ArbitraryTypeReader.*
import net.ceedubs.ficus.readers.ValueReader

import scala.concurrent.duration.*

case class RewardsSettings(
    term: Int,
    termAfterCappedRewardFeature: Int,
    initial: Long,
    minIncrement: Long,
    votingInterval: Int
) {
  require(initial >= 0, "initial must be greater than or equal to 0")
  require(minIncrement > 0, "minIncrement must be greater than 0")
  require(term > 0, "term must be greater than 0")
  require(votingInterval > 0, "votingInterval must be greater than 0")
  require(votingInterval <= term, s"votingInterval must be less than or equal to term($term)")
  require(termAfterCappedRewardFeature > 0, "termAfterCappedRewardFeature must be greater than 0")
  require(
    votingInterval <= termAfterCappedRewardFeature,
    s"votingInterval must be less than or equal to termAfterCappedRewardFeature($termAfterCappedRewardFeature)"
  )

  def nearestTermEnd(activatedAt: Int, height: Int, modifyTerm: Boolean): Int = {
    require(height >= activatedAt)
    val diff         = height - activatedAt + 1
    val modifiedTerm = if (modifyTerm) termAfterCappedRewardFeature else term
    val mul          = math.ceil(diff.toDouble / modifiedTerm).toInt
    activatedAt + mul * modifiedTerm - 1
  }

  def votingWindow(activatedAt: Int, height: Int, modifyTerm: Boolean): Range = {
    val end   = nearestTermEnd(activatedAt, height, modifyTerm)
    val start = end - votingInterval + 1
    if (height >= start) Range.inclusive(start, height)
    else Range(0, 0)
  }
}

object RewardsSettings {
  val MAINNET, TESTNET, STAGENET = apply(
    100000,
    50000,
    6 * Constants.UnitsInWave,
    50000000,
    10000
  )
}

case class FunctionalitySettings(
    featureCheckBlocksPeriod: Int = 1000,
    blocksForFeatureActivation: Int = 800,
    generationBalanceDepthFrom50To1000AfterHeight: Int = 0,
    blockVersion3AfterHeight: Int = 0,
    preActivatedFeatures: Map[Short, Int] = Map.empty,
    doubleFeaturesPeriodsAfterHeight: Int = Int.MaxValue,
    maxTransactionTimeBackOffset: FiniteDuration = 120.minutes,
    maxTransactionTimeForwardOffset: FiniteDuration = 90.minutes,
    lastTimeBasedForkParameter: Long = 0L,
    leaseExpiration: Int = 1000000,
    estimatorPreCheckHeight: Int = 0,
    minAssetInfoUpdateInterval: Int = 100000,
    minBlockTime: FiniteDuration = 15.seconds,
    delayDelta: Int = 8,
    estimationOverflowFixHeight: Int = 0,
    estimatorSumOverflowFixHeight: Int = 0,
    enforceTransferValidationAfter: Int = 0,
    ethInvokePaymentsCheckHeight: Int = 0,
    daoAddress: Option[String] = None,
    xtnBuybackAddress: Option[String] = None,
    xtnBuybackRewardPeriod: Int = Int.MaxValue,
    lightNodeBlockFieldsAbsenceInterval: Int = 1000,
    blockRewardBoostPeriod: Int = 1000,
    paymentsCheckHeight: Int = 0
) {
  val allowLeasedBalanceTransferUntilHeight: Int              = blockVersion3AfterHeight
  val allowTemporaryNegativeUntil: Long                       = lastTimeBasedForkParameter
  val minimalGeneratingBalanceAfter: Long                     = lastTimeBasedForkParameter
  val allowTransactionsFromFutureUntil: Long                  = lastTimeBasedForkParameter
  val allowUnissuedAssetsUntil: Long                          = lastTimeBasedForkParameter
  val allowInvalidReissueInSameBlockUntilTimestamp: Long      = lastTimeBasedForkParameter
  val allowMultipleLeaseCancelTransactionUntilTimestamp: Long = lastTimeBasedForkParameter

  lazy val daoAddressParsed: Either[String, Option[Address]] =
    daoAddress.traverse(Address.fromString(_)).leftMap(_ => "Incorrect dao-address")
  lazy val xtnBuybackAddressParsed: Either[String, Option[Address]] =
    xtnBuybackAddress.traverse(Address.fromString(_)).leftMap(_ => "Incorrect xtn-buyback-address")

  require(featureCheckBlocksPeriod > 0, "featureCheckBlocksPeriod must be greater than 0")
  require(
    (blocksForFeatureActivation > 0) && (blocksForFeatureActivation <= featureCheckBlocksPeriod),
    s"blocksForFeatureActivation must be in range 1 to $featureCheckBlocksPeriod"
  )
  require(minAssetInfoUpdateInterval >= 0, "minAssetInfoUpdateInterval must be greater than or equal to 0")

  def activationWindowSize(height: Int): Int =
    featureCheckBlocksPeriod * (if (height <= doubleFeaturesPeriodsAfterHeight) 1 else 2)

  def activationWindow(height: Int): Range =
    if (height < 1) Range(0, 0)
    else {
      val ws = activationWindowSize(height)
      Range.inclusive((height - 1) / ws * ws + 1, ((height - 1) / ws + 1) * ws)
    }

  def blocksForFeatureActivation(height: Int): Int =
    blocksForFeatureActivation * (if (height <= doubleFeaturesPeriodsAfterHeight) 1 else 2)

  def generatingBalanceDepth(height: Int): Int =
    if (height >= generationBalanceDepthFrom50To1000AfterHeight) 1000 else 50
}

object FunctionalitySettings {
  val MAINNET: FunctionalitySettings = apply(
    featureCheckBlocksPeriod = 5000,
    blocksForFeatureActivation = 4000,
    generationBalanceDepthFrom50To1000AfterHeight = 232000,
    blockVersion3AfterHeight = 795000,
    doubleFeaturesPeriodsAfterHeight = 810000,
    lastTimeBasedForkParameter = 1530161445559L,
    estimatorPreCheckHeight = 1847610,
    estimationOverflowFixHeight = 2858710,
    estimatorSumOverflowFixHeight = 2897510,
    enforceTransferValidationAfter = 2959447,
    daoAddress = Some("3PEgG7eZHLFhcfsTSaYxgRhZsh4AxMvA4Ms"),
    xtnBuybackAddress = Some("3PFjHWuH6WXNJbwnfLHqNFBpwBS5dkYjTfv"),
    xtnBuybackRewardPeriod = 100000,
    blockRewardBoostPeriod = 300_000,
    paymentsCheckHeight = 4303300
  )

  val TESTNET: FunctionalitySettings = apply(
    featureCheckBlocksPeriod = 3000,
    blocksForFeatureActivation = 2700,
    blockVersion3AfterHeight = 161700,
    doubleFeaturesPeriodsAfterHeight = Int.MaxValue,
    lastTimeBasedForkParameter = 1492560000000L,
    estimatorPreCheckHeight = 817380,
    estimationOverflowFixHeight = 1793770,
    estimatorSumOverflowFixHeight = 1832520,
    enforceTransferValidationAfter = 1698800,
    daoAddress = Some("3Myb6G8DkdBb8YcZzhrky65HrmiNuac3kvS"),
    xtnBuybackAddress = Some("3N13KQpdY3UU7JkWUBD9kN7t7xuUgeyYMTT"),
    xtnBuybackRewardPeriod = 2000,
    blockRewardBoostPeriod = 2_000
  )

  val STAGENET: FunctionalitySettings = apply(
    featureCheckBlocksPeriod = 100,
    blocksForFeatureActivation = 40,
    preActivatedFeatures = (1 to 13).map(_.toShort -> 0).toMap,
    doubleFeaturesPeriodsAfterHeight = 1000000000,
    minAssetInfoUpdateInterval = 10,
    estimationOverflowFixHeight = 1078680,
    estimatorSumOverflowFixHeight = 1097419,
    ethInvokePaymentsCheckHeight = 1311110,
    daoAddress = Some("3MaFVH1vTv18FjBRugSRebx259D7xtRh9ic"),
    xtnBuybackAddress = Some("3MbhiRiLFLJ1EVKNP9npRszcLLQDjwnFfZM"),
    xtnBuybackRewardPeriod = 1000,
    paymentsCheckHeight = 2195900
  )
}

case class GenesisTransactionSettings(recipient: String, amount: Long)

case class GenesisSettings(
    blockTimestamp: Long,
    timestamp: Long,
    initialBalance: Long,
    signature: Option[ByteStr],
    transactions: Seq[GenesisTransactionSettings],
    initialBaseTarget: Long,
    averageBlockDelay: FiniteDuration
)

object GenesisSettings { // TODO: Move to network-defaults.conf
  val MAINNET: GenesisSettings = GenesisSettings(
    1460678400000L,
    1465742577614L,
    Constants.UnitsInWave * Constants.TotalWaves,
    ByteStr.decodeBase58("FSH8eAAzZNqnG8xgTZtz5xuLqXySsXgAjmFEC25hXMbEufiGjqWPnGCZFt6gLiVLJny16ipxRNAkkzjjhqTjBE2").toOption,
    List(
      GenesisTransactionSettings("3PAWwWa6GbwcJaFzwqXQN5KQm7H96Y7SHTQ", Constants.UnitsInWave * Constants.TotalWaves - 5 * Constants.UnitsInWave),
      GenesisTransactionSettings("3P8JdJGYc7vaLu4UXUZc1iRLdzrkGtdCyJM", Constants.UnitsInWave),
      GenesisTransactionSettings("3PAGPDPqnGkyhcihyjMHe9v36Y4hkAh9yDy", Constants.UnitsInWave),
      GenesisTransactionSettings("3P9o3ZYwtHkaU1KxsKkFjJqJKS3dLHLC9oF", Constants.UnitsInWave),
      GenesisTransactionSettings("3PJaDyprvekvPXPuAtxrapacuDJopgJRaU3", Constants.UnitsInWave),
      GenesisTransactionSettings("3PBWXDFUc86N2EQxKJmW8eFco65xTyMZx6J", Constants.UnitsInWave)
    ),
    153722867L,
    60.seconds
  )

  val TESTNET: GenesisSettings = GenesisSettings(
    1460678400000L,
    1478000000000L,
    Constants.UnitsInWave * Constants.TotalWaves,
    ByteStr.decodeBase58("5uqnLK3Z9eiot6FyYBfwUnbyid3abicQbAZjz38GQ1Q8XigQMxTK4C1zNkqS1SVw7FqSidbZKxWAKLVoEsp4nNqa").toOption,
    List(
      GenesisTransactionSettings("3My3KZgFQ3CrVHgz6vGRt8687sH4oAA1qp8", (Constants.UnitsInWave * Constants.TotalWaves * 0.04).toLong),
      GenesisTransactionSettings("3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8", (Constants.UnitsInWave * Constants.TotalWaves * 0.02).toLong),
      GenesisTransactionSettings("3N5GRqzDBhjVXnCn44baHcz2GoZy5qLxtTh", (Constants.UnitsInWave * Constants.TotalWaves * 0.02).toLong),
      GenesisTransactionSettings("3NCBMxgdghg4tUhEEffSXy11L6hUi6fcBpd", (Constants.UnitsInWave * Constants.TotalWaves * 0.02).toLong),
      GenesisTransactionSettings(
        "3N18z4B8kyyQ96PhN5eyhCAbg4j49CgwZJx",
        (Constants.UnitsInWave * Constants.TotalWaves - Constants.UnitsInWave * Constants.TotalWaves * 0.1).toLong
      )
    ),
    153722867L,
    60.seconds
  )

  val STAGENET: GenesisSettings = GenesisSettings(
    1561705836768L,
    1561705836768L,
    Constants.UnitsInWave * Constants.TotalWaves,
    ByteStr.decodeBase58("2EaaguFPgrJ1bbMAFrPw2bi6i7kqjgvxsFj8YGqrKR7hT54ZvwmzZ3LHMm4qR7i7QB5cacp8XdkLMJyvjFkt8VgN").toOption,
    List(
      GenesisTransactionSettings("3Mi63XiwniEj6mTC557pxdRDddtpj7fZMMw", Constants.UnitsInWave * Constants.TotalWaves)
    ),
    5000,
    1.minute
  )
}

case class BlockchainSettings(
    addressSchemeCharacter: Char,
    functionalitySettings: FunctionalitySettings,
    genesisSettings: GenesisSettings,
    rewardsSettings: RewardsSettings
)

private[settings] object BlockchainType {
  val STAGENET = "STAGENET"
  val TESTNET  = "TESTNET"
  val MAINNET  = "MAINNET"
}

object BlockchainSettings {
  implicit val valueReader: ValueReader[BlockchainSettings] =
    (cfg: Config, path: String) => fromConfig(cfg.getConfig(path))

  // @deprecated("Use config.as[BlockchainSettings]", "0.17.0")
  def fromRootConfig(config: Config): BlockchainSettings = config.as[BlockchainSettings]("waves.blockchain")

  private[this] def fromConfig(config: Config): BlockchainSettings = {
    val blockchainType = config.as[String]("type").toUpperCase
    val (addressSchemeCharacter, functionalitySettings, genesisSettings, rewardsSettings) = blockchainType match {
      case BlockchainType.STAGENET =>
        ('S', FunctionalitySettings.STAGENET, GenesisSettings.STAGENET, RewardsSettings.STAGENET)
      case BlockchainType.TESTNET =>
        ('T', FunctionalitySettings.TESTNET, GenesisSettings.TESTNET, RewardsSettings.TESTNET)
      case BlockchainType.MAINNET =>
        ('W', FunctionalitySettings.MAINNET, GenesisSettings.MAINNET, RewardsSettings.MAINNET)
      case _ => // Custom
        val networkId     = config.as[String](s"custom.address-scheme-character").charAt(0)
        val functionality = config.as[FunctionalitySettings](s"custom.functionality")
        val genesis       = config.as[GenesisSettings](s"custom.genesis")
        val rewards       = config.as[RewardsSettings](s"custom.rewards")
        require(functionality.minBlockTime <= genesis.averageBlockDelay, "minBlockTime should be <= averageBlockDelay")
        (networkId, functionality, genesis, rewards)
    }

    BlockchainSettings(
      addressSchemeCharacter = addressSchemeCharacter,
      functionalitySettings = functionalitySettings,
      genesisSettings = genesisSettings,
      rewardsSettings = rewardsSettings
    )
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy