Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BaseTarget calculation algorithm fixing the blocktimes #94

Merged
merged 3 commits into from
Jun 3, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions build-submodules.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to write sbt commands for such a tasks


for submodule in basics transaction consensus; do
sbt "project $submodule" "clean" "publishLocal"
done
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ import scorex.utils.{NTP, ScorexLogging}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.{Failure, Try}


class NxtLikeConsensusModule(AvgDelay: Long = 5.seconds.toMillis)
class NxtLikeConsensusModule(AvgDelayInSeconds: Long = 60)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's update version on line 23 to val version = 2: Byte

Copy link
Contributor

@gagarin55 gagarin55 Jun 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AvgDelay will pass from our Waves Application(proof), we don't need to change its default value (5 sec) in Scorex

extends LagonakiConsensusModule[NxtLikeConsensusBlockData] with ScorexLogging {

import NxtLikeConsensusModule._
Expand All @@ -37,7 +36,7 @@ class NxtLikeConsensusModule(AvgDelay: Long = 5.seconds.toMillis)
val generator = block.signerDataField.value.generator

//check baseTarget
val cbt = calcBaseTarget(prevBlockData, prevTime, blockTime)
val cbt = calcBaseTarget(prev, blockTime)
val bbt = blockData.baseTarget
require(cbt == bbt, s"Block's basetarget is wrong, calculated: $cbt, block contains: $bbt")

Expand All @@ -48,7 +47,7 @@ class NxtLikeConsensusModule(AvgDelay: Long = 5.seconds.toMillis)
s"Block's generation signature is wrong, calculated: ${calcGs.mkString}, block contains: ${blockGs.mkString}")

//check hit < target
calcHit(prevBlockData, generator) < calcTarget(prevBlockData, prevTime, generator)
calcHit(prevBlockData, generator) < calcTarget(prev, blockTime, effectiveBalance(generator))
}.recoverWith { case t =>
log.error("Error while checking a block", t)
Failure(t)
Expand All @@ -63,19 +62,22 @@ class NxtLikeConsensusModule(AvgDelay: Long = 5.seconds.toMillis)

val lastBlockTime = lastBlock.timestampField.value

val currentTime = NTP.correctedTime()
val effBalance = effectiveBalance(account)

val h = calcHit(lastBlockKernelData, account)
val t = calcTarget(lastBlockKernelData, lastBlockTime, account)
val t = calcTarget(lastBlock, currentTime, effBalance)

val eta = (currentTime - lastBlockTime) / 1000

val eta = (NTP.correctedTime() - lastBlockTime) / 1000

log.debug(s"hit: $h, target: $t, generating ${h < t}, eta $eta, " +
s"account: $account " +
s"account balance: ${transactionModule.blockStorage.state.asInstanceOf[BalanceSheet].generationBalance(account)}"
s"account balance: $effBalance"
)

if (h < t) {
val timestamp = NTP.correctedTime()
val btg = calcBaseTarget(lastBlockKernelData, lastBlockTime, timestamp)
val btg = calcBaseTarget(lastBlock, currentTime)
val gs = calcGeneratorSignature(lastBlockKernelData, account)
val consensusData = new NxtLikeConsensusBlockData {
override val generationSignature: Array[Byte] = gs
Expand All @@ -86,7 +88,7 @@ class NxtLikeConsensusModule(AvgDelay: Long = 5.seconds.toMillis)
log.debug(s"Build block with ${unconfirmed.asInstanceOf[Seq[Transaction]].size} transactions")

Future(Some(Block.buildAndSign(version,
timestamp,
currentTime,
lastBlock.uniqueId,
consensusData,
unconfirmed,
Expand All @@ -95,27 +97,53 @@ class NxtLikeConsensusModule(AvgDelay: Long = 5.seconds.toMillis)
} else Future(None)
}

private def effectiveBalance[TT](account: Account)(implicit transactionModule: TransactionModule[TT]) =
transactionModule.blockStorage.state.asInstanceOf[BalanceSheet].balanceWithConfirmations(account.address, EffectiveBalanceDepth)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line length should be <= 120 letters


private def calcGeneratorSignature(lastBlockData: NxtLikeConsensusBlockData, generator: PublicKeyAccount) =
hash(lastBlockData.generationSignature ++ generator.publicKey)

private def calcHit(lastBlockData: NxtLikeConsensusBlockData, generator: PublicKeyAccount): BigInt =
BigInt(1, calcGeneratorSignature(lastBlockData, generator).take(8))

private def calcBaseTarget(lastBlockData: NxtLikeConsensusBlockData,
lastBlockTimestamp: Long,
currentTime: Long): Long = {
val eta = currentTime - lastBlockTimestamp
val prevBt = BigInt(lastBlockData.baseTarget)
val t0 = bounded(prevBt * eta / AvgDelay, prevBt / 2, prevBt * 2)
bounded(t0, 1, Long.MaxValue).toLong
BigInt(1, calcGeneratorSignature(lastBlockData, generator).take(8).reverse)

/**
* BaseTarget calculation algorithm fixing the blocktimes.
*
*/
private def calcBaseTarget[TT](prevBlock: Block, timestamp: Long) (implicit transactionModule: TransactionModule[TT]): Long = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too long line

val height = transactionModule.blockStorage.history.heightOf(prevBlock).get
val prevBaseTarget = consensusBlockData(prevBlock).baseTarget
if (height % 2 == 0) {
val lastBlocks: Seq[Block] = transactionModule.blockStorage.history.lastBlocks(3)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use transactionModule.blockStorage.history.averageDelay(prevBlock, 3) here

val block = lastBlocks.head
val blocktimeAverage = (timestamp - block.timestampField.value) / lastBlocks.size
val bt =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type if on the same line as val, like val bt = if (blocktimeAverage > AvgDelayInSeconds) {

if (blocktimeAverage > AvgDelayInSeconds) {
(prevBaseTarget * Math.min(blocktimeAverage, MaxBlocktimeLimit)) / AvgDelayInSeconds
}
else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use else on the same line with bracket } else {

prevBaseTarget - prevBaseTarget * BaseTargetGamma * (AvgDelayInSeconds - Math.max(blocktimeAverage, MinBlocktimeLimit)) / (AvgDelayInSeconds * 100)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too long line

}
if (bt < 0 || bt > MaxBaseTarget2) {
MaxBaseTarget2
} else if (bt < MinBaseTarget) {
MinBaseTarget
} else {
bt
}
} else {
prevBaseTarget
}
}

protected def calcTarget(lastBlockData: NxtLikeConsensusBlockData,
lastBlockTimestamp: Long,
generator: PublicKeyAccount)(implicit transactionModule: TransactionModule[_]): BigInt = {
val eta = (NTP.correctedTime() - lastBlockTimestamp) / 1000 //in seconds
val effBalance = transactionModule.blockStorage.state.asInstanceOf[BalanceSheet].generationBalance(generator)
BigInt(lastBlockData.baseTarget) * eta * effBalance
private def calcTarget(prevBlock: Block,
timestamp: Long,
effBalance: Long)(implicit transactionModule: TransactionModule[_]): BigInt = {
val prevBlockData = consensusBlockData(prevBlock)
val prevBlockTimestamp = prevBlock.timestampField.value

val eta = (timestamp - prevBlockTimestamp) / 1000 //in seconds
BigInt(prevBlockData.baseTarget) * eta * effBalance
}

private def bounded(value: BigInt, min: BigInt, max: BigInt): BigInt =
Expand Down Expand Up @@ -154,4 +182,13 @@ class NxtLikeConsensusModule(AvgDelay: Long = 5.seconds.toMillis)
object NxtLikeConsensusModule {
val BaseTargetLength = 8
val GeneratorSignatureLength = 32

val MinBlocktimeLimit = 53
val MaxBlocktimeLimit = 67
val BaseTargetGamma = 64
val InitialBaseTarget = 153722867
val MaxBaseTarget2 = InitialBaseTarget * 50
val MinBaseTarget = InitialBaseTarget * 9 / 10

val EffectiveBalanceDepth = 1440
}