mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[NOD-1006] Make use of a pool to avoid excessive allocation of big.Ints (#722)
* [NOD-1006] Make CompactToBig take an out param so that we can reuse the same big.Int in averageTarget. * [NOD-1006] Fix merge errors. * [NOD-1006] Use CompactToBigWithDestination only in averageTarget. * [NOD-1006] Fix refactor errors. * [NOD-1006] Fix refactor errors. * [NOD-1006] Optimize averageTarget with a big.Int pool. * [NOD-1006] Defer releasing bigInts. * [NOD-1006] Use a pool for requiredDifficulty as well. * [NOD-1006] Move the big int pool to utils. * [NOD-1006] Remove unnecessary line.
This commit is contained in:
parent
eb8b841850
commit
e9e1ef4772
@ -2,6 +2,7 @@ package blockdag
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/bigintpool"
|
||||
"github.com/pkg/errors"
|
||||
"math"
|
||||
"math/big"
|
||||
@ -53,13 +54,19 @@ func (window blockWindow) minMaxTimestamps() (min, max int64) {
|
||||
return
|
||||
}
|
||||
|
||||
func (window blockWindow) averageTarget() *big.Int {
|
||||
averageTarget := big.NewInt(0)
|
||||
func (window blockWindow) averageTarget(averageTarget *big.Int) {
|
||||
averageTarget.SetInt64(0)
|
||||
|
||||
target := bigintpool.Acquire(0)
|
||||
defer bigintpool.Release(target)
|
||||
for _, node := range window {
|
||||
target := util.CompactToBig(node.bits)
|
||||
util.CompactToBigWithDestination(node.bits, target)
|
||||
averageTarget.Add(averageTarget, target)
|
||||
}
|
||||
return averageTarget.Div(averageTarget, big.NewInt(int64(len(window))))
|
||||
|
||||
windowLen := bigintpool.Acquire(int64(len(window)))
|
||||
defer bigintpool.Release(windowLen)
|
||||
averageTarget.Div(averageTarget, windowLen)
|
||||
}
|
||||
|
||||
func (window blockWindow) medianTimestamp() (int64, error) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
package blockdag
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"github.com/kaspanet/kaspad/util/bigintpool"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
@ -30,11 +30,20 @@ func (dag *BlockDAG) requiredDifficulty(bluestParent *blockNode, newBlockTime ti
|
||||
// averageWindowTarget * (windowMinTimestamp / (targetTimePerBlock * windowSize))
|
||||
// The result uses integer division which means it will be slightly
|
||||
// rounded down.
|
||||
newTarget := targetsWindow.averageTarget()
|
||||
newTarget := bigintpool.Acquire(0)
|
||||
defer bigintpool.Release(newTarget)
|
||||
windowTimeStampDifference := bigintpool.Acquire(windowMaxTimeStamp - windowMinTimestamp)
|
||||
defer bigintpool.Release(windowTimeStampDifference)
|
||||
targetTimePerBlock := bigintpool.Acquire(dag.targetTimePerBlock)
|
||||
defer bigintpool.Release(targetTimePerBlock)
|
||||
difficultyAdjustmentWindowSize := bigintpool.Acquire(int64(dag.difficultyAdjustmentWindowSize))
|
||||
defer bigintpool.Release(difficultyAdjustmentWindowSize)
|
||||
|
||||
targetsWindow.averageTarget(newTarget)
|
||||
newTarget.
|
||||
Mul(newTarget, big.NewInt(windowMaxTimeStamp-windowMinTimestamp)).
|
||||
Div(newTarget, big.NewInt(dag.targetTimePerBlock)).
|
||||
Div(newTarget, big.NewInt(int64(dag.difficultyAdjustmentWindowSize)))
|
||||
Mul(newTarget, windowTimeStampDifference).
|
||||
Div(newTarget, targetTimePerBlock).
|
||||
Div(newTarget, difficultyAdjustmentWindowSize)
|
||||
if newTarget.Cmp(dag.dagParams.PowMax) > 0 {
|
||||
return dag.powMaxBits
|
||||
}
|
||||
|
25
util/bigintpool/pool.go
Normal file
25
util/bigintpool/pool.go
Normal file
@ -0,0 +1,25 @@
|
||||
package bigintpool
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var bigIntPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return big.NewInt(0)
|
||||
},
|
||||
}
|
||||
|
||||
// Acquire acquires a big.Int from the pool and
|
||||
// initializes it to x.
|
||||
func Acquire(x int64) *big.Int {
|
||||
bigInt := bigIntPool.Get().(*big.Int)
|
||||
bigInt.SetInt64(x)
|
||||
return bigInt
|
||||
}
|
||||
|
||||
// Release returns the given big.Int to the pool.
|
||||
func Release(toRelease *big.Int) {
|
||||
bigIntPool.Put(toRelease)
|
||||
}
|
21
util/math.go
21
util/math.go
@ -53,6 +53,16 @@ func FastLog2Floor(n uint64) uint8 {
|
||||
// The formula to calculate N is:
|
||||
// N = (-1^sign) * mantissa * 256^(exponent-3)
|
||||
func CompactToBig(compact uint32) *big.Int {
|
||||
destination := big.NewInt(0)
|
||||
CompactToBigWithDestination(compact, destination)
|
||||
return destination
|
||||
}
|
||||
|
||||
// CompactToBigWithDestination is a version of CompactToBig that
|
||||
// takes a destination parameter. This is useful for saving memory,
|
||||
// as then the destination big.Int can be reused.
|
||||
// See CompactToBig for further details.
|
||||
func CompactToBigWithDestination(compact uint32, destination *big.Int) {
|
||||
// Extract the mantissa, sign bit, and exponent.
|
||||
mantissa := compact & 0x007fffff
|
||||
isNegative := compact&0x00800000 != 0
|
||||
@ -63,21 +73,18 @@ func CompactToBig(compact uint32) *big.Int {
|
||||
// treat the exponent as the number of bytes and shift the mantissa
|
||||
// right or left accordingly. This is equivalent to:
|
||||
// N = mantissa * 256^(exponent-3)
|
||||
var bn *big.Int
|
||||
if exponent <= 3 {
|
||||
mantissa >>= 8 * (3 - exponent)
|
||||
bn = big.NewInt(int64(mantissa))
|
||||
destination.SetInt64(int64(mantissa))
|
||||
} else {
|
||||
bn = big.NewInt(int64(mantissa))
|
||||
bn.Lsh(bn, 8*(exponent-3))
|
||||
destination.SetInt64(int64(mantissa))
|
||||
destination.Lsh(destination, 8*(exponent-3))
|
||||
}
|
||||
|
||||
// Make it negative if the sign bit is set.
|
||||
if isNegative {
|
||||
bn = bn.Neg(bn)
|
||||
destination.Neg(destination)
|
||||
}
|
||||
|
||||
return bn
|
||||
}
|
||||
|
||||
// BigToCompact converts a whole number N to a compact representation using
|
||||
|
Loading…
x
Reference in New Issue
Block a user