Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ object BlockchainFeatures {
val BoostBlockReward = BlockchainFeature(23, "Boost Block Reward")
val EcrecoverFix = BlockchainFeature(24, "ecrecover fix")
val DeterministicFinality = BlockchainFeature(25, "Deterministic Finality & RIDE V9")
val AdjustedBlockRewardDistribution = BlockchainFeature(26, "Adjusted Block Reward Distribution")

// Not exposed
val ContinuationTransaction = BlockchainFeature(26, "Continuation Transaction")
val LeaseExpiration = BlockchainFeature(27, "Lease Expiration")
val ContinuationTransaction = BlockchainFeature(27, "Continuation Transaction")
val LeaseExpiration = BlockchainFeature(28, "Lease Expiration")

// When next fork-parameter is created, you must replace all uses of the DummyFeature with the new one.
val Dummy = BlockchainFeature(-1, "Non Votable!")
Expand Down Expand Up @@ -62,7 +63,8 @@ object BlockchainFeatures {
LightNode,
BoostBlockReward,
EcrecoverFix,
DeterministicFinality
DeterministicFinality,
AdjustedBlockRewardDistribution
).map(f => f.id -> f).toMap

val implemented: Set[Short] = dict.keySet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,59 @@ object BlockRewardCalculator {
val GuaranteedMinerReward: Long = 2 * Constants.UnitsInWave
val RewardBoost = 10

/** How the block reward is split between the miner, the DAO address and the XTN buyback address once
* [[BlockchainFeatures.CappedReward]] is activated.
*
* @param fullReward
* the block reward at which both the DAO and the XTN buyback addresses receive their maximum shares
* @param guaranteedMinerReward
* the part of the block reward the miner receives regardless of the votes
* @param maxDaoAddressReward
* the maximum share of the DAO address
* @param maxXtnBuybackAddressReward
* the maximum share of the XTN buyback address
* @param daoAddressRemainderPart
* the part of a below-[[fullReward]] block reward left after the guaranteed miner reward that goes to the DAO address
* @param xtnBuybackAddressRemainderPart
* the same for the XTN buyback address
*/
case class RewardDistribution(
fullReward: Long,
guaranteedMinerReward: Long,
maxDaoAddressReward: Long,
maxXtnBuybackAddressReward: Long,
daoAddressRemainderPart: Fraction,
xtnBuybackAddressRemainderPart: Fraction
)

/** 2 (DAO) / 2 (miner) / 2 (XTN buyback) at the initial block reward of 6 waves. */
val DefaultDistribution: RewardDistribution = RewardDistribution(
FullRewardInit,
GuaranteedMinerReward,
MaxAddressReward,
MaxAddressReward,
RemaindRewardAddressPart,
RemaindRewardAddressPart
)

/** 10 (DAO) / 8 (miner) / 2 (XTN buyback) at the block reward of 20 waves, used after the activation of
* [[BlockchainFeatures.AdjustedBlockRewardDistribution]]. 20 waves is the amount the block reward is reset to at the activation height, it stays
* votable afterwards.
*/
val AdjustedFullReward: Long = 20 * Constants.UnitsInWave
val AdjustedDaoAddressReward: Long = 10 * Constants.UnitsInWave
val AdjustedXtnBuybackAddressReward: Long = 2 * Constants.UnitsInWave
val AdjustedGuaranteedMinerReward: Long = AdjustedFullReward - AdjustedDaoAddressReward - AdjustedXtnBuybackAddressReward

val AdjustedDistribution: RewardDistribution = RewardDistribution(
AdjustedFullReward,
AdjustedGuaranteedMinerReward,
AdjustedDaoAddressReward,
AdjustedXtnBuybackAddressReward,
Fraction(5, 6),
Fraction(1, 6)
)

def getBlockRewardShares(
height: Height,
fullBlockReward: Long,
Expand All @@ -34,24 +87,32 @@ object BlockRewardCalculator {
val blockRewardDistributionHeight = blockchain.featureActivationHeight(BlockchainFeatures.BlockRewardDistribution).getOrElse(Height(Int.MaxValue))
val cappedRewardHeight = blockchain.featureActivationHeight(BlockchainFeatures.CappedReward).getOrElse(Height(Int.MaxValue))
val ceaseXtnBuybackHeight = blockchain.featureActivationHeight(BlockchainFeatures.CeaseXtnBuyback).getOrElse(Height(Int.MaxValue))
val adjustedRewardDistributionHeight =
blockchain.featureActivationHeight(BlockchainFeatures.AdjustedBlockRewardDistribution).getOrElse(Height(Int.MaxValue))

if (height >= blockRewardDistributionHeight) {
val modifiedXtnBuybackAddress = xtnBuybackAddress.filter { _ =>
height < ceaseXtnBuybackHeight ||
height < blockRewardDistributionHeight + blockchain.settings.functionalitySettings.xtnBuybackRewardPeriod
}
if (height >= cappedRewardHeight) {
if (fullBlockReward < GuaranteedMinerReward) {
val distribution = if (height >= adjustedRewardDistributionHeight) AdjustedDistribution else DefaultDistribution

if (fullBlockReward < distribution.guaranteedMinerReward) {
BlockRewardShares(fullBlockReward, 0, 0)
} else if (fullBlockReward < FullRewardInit) {
} else if (fullBlockReward < distribution.fullReward) {
val remainder = fullBlockReward - distribution.guaranteedMinerReward
calculateRewards(
fullBlockReward,
RemaindRewardAddressPart.apply(fullBlockReward - GuaranteedMinerReward),
daoAddress,
modifiedXtnBuybackAddress
daoAddress.fold(0L)(_ => distribution.daoAddressRemainderPart(remainder)),
modifiedXtnBuybackAddress.fold(0L)(_ => distribution.xtnBuybackAddressRemainderPart(remainder))
)
} else {
calculateRewards(fullBlockReward, MaxAddressReward, daoAddress, modifiedXtnBuybackAddress)
calculateRewards(
fullBlockReward,
daoAddress.fold(0L)(_ => distribution.maxDaoAddressReward),
modifiedXtnBuybackAddress.fold(0L)(_ => distribution.maxXtnBuybackAddressReward)
)
}
} else {
calculateRewards(fullBlockReward, CurrentBlockRewardPart.apply(fullBlockReward), daoAddress, modifiedXtnBuybackAddress)
Expand Down Expand Up @@ -79,13 +140,18 @@ object BlockRewardCalculator {
getSortedBlockRewardShares(height, fullBlockReward, generator, blockchain)
}

private def calculateRewards(blockReward: Long, addressReward: Long, daoAddress: Option[Address], xtnBuybackAddress: Option[Address]) = {
val daoAddressReward = daoAddress.fold(0L) { _ => addressReward }
val xtnBuybackReward = xtnBuybackAddress.fold(0L) { _ => addressReward }
private def calculateRewards(
blockReward: Long,
addressReward: Long,
daoAddress: Option[Address],
xtnBuybackAddress: Option[Address]
): BlockRewardShares =
calculateRewards(blockReward, daoAddress.fold(0L)(_ => addressReward), xtnBuybackAddress.fold(0L)(_ => addressReward))

private def calculateRewards(blockReward: Long, daoAddressReward: Long, xtnBuybackReward: Long) =
BlockRewardShares(
blockReward - daoAddressReward - xtnBuybackReward,
daoAddressReward,
xtnBuybackReward
)
}
}
15 changes: 9 additions & 6 deletions node/src/main/scala/com/wavesplatform/state/Blockchain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,16 @@ object Blockchain {
.featureActivationHeight(BlockchainFeatures.LightNode)
.exists(Height(height) >= _ + blockchain.settings.functionalitySettings.lightNodeBlockFieldsAbsenceInterval)

// AdjustedBlockRewardDistribution supersedes BoostBlockReward: the block reward it votes on is already the full amount issued per block
def blockRewardBoost(height: Height): Int =
blockchain
.featureActivationHeight(BlockchainFeatures.BoostBlockReward)
.filter { boostHeight =>
boostHeight <= height && height < boostHeight + blockchain.settings.functionalitySettings.blockRewardBoostPeriod
}
.fold(1)(_ => BlockRewardCalculator.RewardBoost)
if (isFeatureActivated(BlockchainFeatures.AdjustedBlockRewardDistribution, height.toInt)) 1
else
blockchain
.featureActivationHeight(BlockchainFeatures.BoostBlockReward)
.filter { boostHeight =>
boostHeight <= height && height < boostHeight + blockchain.settings.functionalitySettings.blockRewardBoostPeriod
}
.fold(1)(_ => BlockRewardCalculator.RewardBoost)

/** @return None, if DeterministicFinality is not activated for provided height
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ class BlockchainUpdaterImpl(
Some(currentReward)
}
.orElse(lastBlockReward)
.map { reward =>
// AdjustedBlockRewardDistribution resets the block reward to its own initial value at the activation height, the voting continues from there
if (this.featureActivationHeight(BlockchainFeatures.AdjustedBlockRewardDistribution).contains(nextHeight))
BlockRewardCalculator.AdjustedFullReward
else reward
}
}

/** Referenced blockchain for mining or appending new block that references the latest block in blockchain or a microblock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,16 @@ object EthereumTransactionDiff {
!(tx.signerKeyBigInt().toByteArray.length < EthereumKeyLength) || blockchain.isFeatureActivated(BlockchainFeatures.ConsensusImprovements)
)("Invalid public key")
_ <- Either.raiseWhen(
tx.longChainId()
.exists(_ != AddressScheme.current.chainId) && blockchain.isFeatureActivated(BlockchainFeatures.DeterministicFinality)
tx.longChainId().exists(_ != AddressScheme.current.chainId) && (
blockchain.isFeatureActivated(BlockchainFeatures.DeterministicFinality) ||
blockchain.isFeatureActivated(BlockchainFeatures.AdjustedBlockRewardDistribution)
)
)(s"Transaction chain ID ${tx.longChainId()} does not match current chain ID ${AddressScheme.current.chainId}")
_ <- Either.raiseWhen(
!tx.ecdsaSignature().isCanonical && blockchain.isFeatureActivated(BlockchainFeatures.DeterministicFinality)
!tx.ecdsaSignature().isCanonical && (
blockchain.isFeatureActivated(BlockchainFeatures.DeterministicFinality) ||
blockchain.isFeatureActivated(BlockchainFeatures.AdjustedBlockRewardDistribution)
)
)("Non-canonical ECDSA signature")
} yield ()).leftMap(GenericError.apply)
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,10 @@ object ExchangeTransactionDiff {
GenericError("Invalid order signature format")
)
_ <- Either.raiseWhen(
signature.size > 65 && blockchain.isFeatureActivated(BlockchainFeatures.DeterministicFinality)
signature.size > 65 && (
blockchain.isFeatureActivated(BlockchainFeatures.DeterministicFinality) ||
blockchain.isFeatureActivated(BlockchainFeatures.AdjustedBlockRewardDistribution)
)
)(GenericError("Invalid order signature format"))
} yield ()
case _ => Right(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ object DomainPresets {

val DeterministicFinality: WavesSettings = TransactionStateSnapshot.addFeatures(BlockchainFeatures.DeterministicFinality)

val AdjustedBlockRewardDistribution: WavesSettings =
DeterministicFinality.addFeatures(BlockchainFeatures.AdjustedBlockRewardDistribution)

def settingsForRide(version: StdLibVersion): WavesSettings =
version match {
case V1 => RideV3
Expand Down
Loading
Loading