blockchain: utilize CalcNextReqStakeDifficulty in fullblocktests.

previously fullblocktests entries required in-depth knowledge of the
stake tree in order to retrieve the prevailing ticket price.
`ticketPrice := b.STransactions[5].TxOut[0].Value`
This commit is contained in:
Donald Adu-Poku 2018-05-06 00:55:34 +00:00 committed by Dave Collins
parent 75432b3c96
commit 63f2913e08
2 changed files with 53 additions and 44 deletions

View File

@ -888,47 +888,15 @@ func (g *Generator) CalcNextRequiredDifficulty() uint32 {
return uint32(nextDiff)
}
// CalcNextRequiredStakeDifficulty returns the required stake difficulty (aka
// ticket price) for the block after the current tip block the generator is
// CalcNextReqStakeDifficulty returns the required stake difficulty (aka
// ticket price) for the block after the provided block the generator is
// associated with.
//
// An overview of the algorithm is as follows:
// 1) Use the minimum value for any blocks before any tickets could have
// possibly been purchased due to coinbase maturity requirements
// 2) Return 0 if the current tip block stake difficulty is 0. This is a
// safety check against a condition that should never actually happen.
// 3) Use the previous block's difficulty if the next block is not at a retarget
// interval
// 4) Calculate the ideal retarget difficulty for each window based on the
// actual pool size in the window versus the target pool size skewed by a
// constant factor to weight the ticket pool size instead of the tickets per
// block and exponentially weight each difficulty such that the most recent
// window has the highest weight
// 5) Calculate the pool size retarget difficulty based on the exponential
// weighted average and ensure it is limited to the max retarget adjustment
// factor -- This is the first metric used to calculate the final difficulty
// 6) Calculate the ideal retarget difficulty for each window based on the
// actual new tickets in the window versus the target new tickets per window
// and exponentially weight each difficulty such that the most recent window
// has the highest weight
// 7) Calculate the tickets per window retarget difficulty based on the
// exponential weighted average and ensure it is limited to the max retarget
// adjustment factor
// 8) Calculate the final difficulty by averaging the pool size retarget
// difficulty from #5 and the tickets per window retarget difficulty from #7
// using scaled multiplication and ensure it is limited to the max retarget
// adjustment factor
//
// NOTE: In order to simplify the test code, this implementation does not use
// big integers so it will NOT match the actual consensus code for really big
// numbers. However, the parameters on simnet and the pool sizes used in these
// tests are low enough that this is not an issue for the tests. Anyone looking
// at this code should NOT use it for mainnet calculations as is since it will
// not always yield the correct results.
func (g *Generator) CalcNextRequiredStakeDifficulty() int64 {
// See the documentation of CalcNextRequiredStakeDifficulty for more details.
func (g *Generator) CalcNextReqStakeDifficulty(prevBlock *wire.MsgBlock) int64 {
// Stake difficulty before any tickets could possibly be purchased is
// the minimum value.
nextHeight := g.tip.Header.Height + 1
nextHeight := prevBlock.Header.Height + 1
stakeDiffStartHeight := uint32(g.params.CoinbaseMaturity) + 1
if nextHeight < stakeDiffStartHeight {
return g.params.MinimumStakeDiff
@ -960,9 +928,9 @@ func (g *Generator) CalcNextRequiredStakeDifficulty() int64 {
var weightedPoolSizeSum, weightSum uint64
ticketsPerBlock := int64(g.params.TicketsPerBlock)
targetPoolSize := ticketsPerBlock * int64(g.params.TicketPoolSize)
block := prevBlock
numWindows := g.params.StakeDiffWindows
weightAlpha := g.params.StakeDiffAlpha
block := g.tip
for i := int64(0); i < numWindows; i++ {
// Get the pool size for the block at the start of the window.
// Use zero if there are not yet enough blocks left to cover the
@ -1020,7 +988,7 @@ func (g *Generator) CalcNextRequiredStakeDifficulty() int64 {
// per window and exponentially weight them.
var weightedTicketsSum uint64
targetTicketsPerWindow := ticketsPerBlock * windowSize
block = g.tip
block = prevBlock
for i := int64(0); i < numWindows; i++ {
// Since the difficulty for the next block after the current tip
// is being calculated and there is no such block yet, the sum
@ -1078,6 +1046,47 @@ func (g *Generator) CalcNextRequiredStakeDifficulty() int64 {
return nextDiff
}
// CalcNextRequiredStakeDifficulty returns the required stake difficulty (aka
// ticket price) for the block after the current tip block the generator is
// associated with.
//
// An overview of the algorithm is as follows:
// 1) Use the minimum value for any blocks before any tickets could have
// possibly been purchased due to coinbase maturity requirements
// 2) Return 0 if the current tip block stake difficulty is 0. This is a
// safety check against a condition that should never actually happen.
// 3) Use the previous block's difficulty if the next block is not at a retarget
// interval
// 4) Calculate the ideal retarget difficulty for each window based on the
// actual pool size in the window versus the target pool size skewed by a
// constant factor to weight the ticket pool size instead of the tickets per
// block and exponentially weight each difficulty such that the most recent
// window has the highest weight
// 5) Calculate the pool size retarget difficulty based on the exponential
// weighted average and ensure it is limited to the max retarget adjustment
// factor -- This is the first metric used to calculate the final difficulty
// 6) Calculate the ideal retarget difficulty for each window based on the
// actual new tickets in the window versus the target new tickets per window
// and exponentially weight each difficulty such that the most recent window
// has the highest weight
// 7) Calculate the tickets per window retarget difficulty based on the
// exponential weighted average and ensure it is limited to the max retarget
// adjustment factor
// 8) Calculate the final difficulty by averaging the pool size retarget
// difficulty from #5 and the tickets per window retarget difficulty from #7
// using scaled multiplication and ensure it is limited to the max retarget
// adjustment factor
//
// NOTE: In order to simplify the test code, this implementation does not use
// big integers so it will NOT match the actual consensus code for really big
// numbers. However, the parameters on simnet and the pool sizes used in these
// tests are low enough that this is not an issue for the tests. Anyone looking
// at this code should NOT use it for mainnet calculations as is since it will
// not always yield the correct results.
func (g *Generator) CalcNextRequiredStakeDifficulty() int64 {
return g.CalcNextReqStakeDifficulty(g.tip)
}
// hash256prng is a determinstic pseudorandom number generator that uses a
// 256-bit secure hashing function to generate random uint32s starting from
// an initial seed.

View File

@ -1325,7 +1325,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
g.SetTip("bsl5")
g.NextBlock("bv15", outs[9], ticketOuts[9], func(b *wire.MsgBlock) {
ticketFee := dcrutil.Amount(2)
ticketPrice := dcrutil.Amount(g.CalcNextRequiredStakeDifficulty())
ticketPrice := dcrutil.Amount(g.CalcNextReqStakeDifficulty(g.Tip()))
ticketPrice--
b.STransactions[5].TxOut[1].PkScript =
chaingen.PurchaseCommitmentScript(g.P2shOpTrueAddr(),
@ -1347,7 +1347,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
prevBlock := g.Tip()
spend := chaingen.MakeSpendableOut(prevBlock, 1, 0)
ticketPrice := dcrutil.Amount(b.STransactions[5].TxOut[0].Value)
ticketPrice := dcrutil.Amount(g.CalcNextReqStakeDifficulty(g.Tip()))
ticket := g.CreateTicketPurchaseTx(&spend, ticketPrice, lowFee)
b.AddSTransaction(ticket)
b.Header.FreshStake++
@ -2015,7 +2015,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
g.SetTip("brs3")
g.NextBlock("bmf25", outs[15], ticketOuts[15], func(b *wire.MsgBlock) {
spendOut := chaingen.MakeSpendableStakeOut(b, 0, 2)
ticketPrice := dcrutil.Amount(b.STransactions[5].TxOut[0].Value)
ticketPrice := dcrutil.Amount(g.CalcNextReqStakeDifficulty(g.Tip()))
ticket := g.CreateTicketPurchaseTx(&spendOut, ticketPrice, lowFee)
b.AddSTransaction(ticket)
b.Header.FreshStake++
@ -2083,7 +2083,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
g.SetTip("brs3")
g.NextBlock("bmf31", outs[15], ticketOuts[15], func(b *wire.MsgBlock) {
spend := chaingen.MakeSpendableOut(b, 0, 0)
ticketPrice := dcrutil.Amount(b.STransactions[5].TxOut[0].Value)
ticketPrice := dcrutil.Amount(g.CalcNextReqStakeDifficulty(g.Tip()))
ticket := g.CreateTicketPurchaseTx(&spend, ticketPrice, lowFee)
b.AddSTransaction(ticket)
b.Header.FreshStake++
@ -2142,7 +2142,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
g.SetTip("brs3")
g.NextBlock("bmf35", outs[15], ticketOuts[15], func(b *wire.MsgBlock) {
spend := chaingen.MakeSpendableStakeOut(b, 5, 2)
ticketPrice := dcrutil.Amount(b.STransactions[5].TxOut[0].Value)
ticketPrice := dcrutil.Amount(g.CalcNextReqStakeDifficulty(g.Tip()))
ticket := g.CreateTicketPurchaseTx(&spend, ticketPrice, lowFee)
b.AddSTransaction(ticket)
b.Header.FreshStake++