forkplan9.go raw

   1  package blockchain
   2  
   3  import (
   4  	"fmt"
   5  	bits2 "github.com/p9c/p9/pkg/bits"
   6  	"github.com/p9c/p9/pkg/fork"
   7  	"math/big"
   8  	"strings"
   9  	
  10  	"github.com/VividCortex/ewma"
  11  	
  12  	"github.com/p9c/p9/pkg/wire"
  13  )
  14  
  15  // GetAlgStamps ...
  16  func GetAlgStamps(algoName string, startHeight int32, lastNode *BlockNode) (last *BlockNode,
  17  	found bool, algStamps []int64, version int32,
  18  ) {
  19  	
  20  	version = fork.P9Algos[algoName].Version
  21  	for ln := lastNode; ln != nil && ln.height > startHeight &&
  22  		len(algStamps) <= int(fork.List[1].AveragingInterval); ln = ln.
  23  		RelativeAncestor(1) {
  24  		if ln.version == version && ln.height > startHeight {
  25  			algStamps = append(algStamps, ln.timestamp)
  26  			if !found {
  27  				found = true
  28  				last = ln
  29  			}
  30  		}
  31  	}
  32  	// D.Ln(algStamps)
  33  	// reverse order of stamps
  34  	for i := 0; i < len(algStamps)/2; i++ {
  35  		algStamps[i], algStamps[len(algStamps)-i-1] = algStamps[len(
  36  			algStamps,
  37  		)-i-1], algStamps[i]
  38  	}
  39  	// D.Ln(algStamps)
  40  	return
  41  }
  42  
  43  func GetAllStamps(startHeight int32, lastNode *BlockNode) (allStamps []int64) {
  44  	
  45  	for ln := lastNode; ln != nil && ln.height > startHeight &&
  46  		len(allStamps) <= int(fork.List[1].AveragingInterval); ln = ln.RelativeAncestor(1) {
  47  		allStamps = append(allStamps, ln.timestamp)
  48  	}
  49  	// D.Ln(allStamps)
  50  	// reverse order of stamps
  51  	for i := 0; i < len(allStamps)/2; i++ {
  52  		allStamps[i], allStamps[len(allStamps)-i-1] =
  53  			allStamps[len(allStamps)-i-1], allStamps[i]
  54  	}
  55  	// D.Ln(allStamps)
  56  	return
  57  }
  58  
  59  func GetAll(allStamps []int64) (allAv, allAdj float64) {
  60  	allAdj = 1
  61  	allAv = fork.P9Average
  62  	// calculate intervals
  63  	allIntervals := make([]float64, len(allStamps)-1)
  64  	for i := range allStamps {
  65  		if i > 0 {
  66  			r := allStamps[i] - allStamps[i-1]
  67  			allIntervals[i-1] = float64(r)
  68  		}
  69  	}
  70  	// D.Ln(allStamps)
  71  	// calculate exponential weighted moving average from intervals
  72  	aewma := ewma.NewMovingAverage()
  73  	for _, x := range allIntervals {
  74  		aewma.Add(x)
  75  	}
  76  	allAv = aewma.Value()
  77  	// W.Ln(allAv)
  78  	if allAv != 0 {
  79  		allAdj = allAv / fork.P9Average
  80  	}
  81  	return
  82  }
  83  
  84  func GetAlg(algStamps []int64, targetTimePerBlock float64) (algAv, algAdj float64) {
  85  	// calculate intervals
  86  	algIntervals := make([]int64, len(algStamps)-1)
  87  	for i := range algStamps {
  88  		if i > 0 {
  89  			r := algStamps[i] - algStamps[i-1]
  90  			algIntervals[i-1] = r
  91  		}
  92  	}
  93  	// D.Ln(algStamps)
  94  	// calculate exponential weighted moving average from intervals
  95  	gewma := ewma.NewMovingAverage()
  96  	for _, x := range algIntervals {
  97  		gewma.Add(float64(x))
  98  	}
  99  	algAv = gewma.Value()
 100  	if algAv != 0 {
 101  		algAdj = algAv / targetTimePerBlock
 102  	}
 103  	return
 104  }
 105  
 106  // CalcNextRequiredDifficultyPlan9 returns the consensus difficulty adjustment by processing recent past blocks
 107  func (b *BlockChain) CalcNextRequiredDifficultyPlan9(lastNodeP *BlockNode, algoName string,
 108  	l bool,
 109  ) (newTargetBits uint32, adjustment float64, e error) {
 110  	lastNode := lastNodeP
 111  	
 112  	algoVer := fork.GetAlgoVer(algoName, lastNode.height+1)
 113  	ttpb := float64(fork.List[1].Algos[algoName].VersionInterval)
 114  	newTargetBits = fork.SecondPowLimitBits
 115  	const minAvSamples = 3
 116  	adjustment = 1
 117  	var algAdj, allAdj, algAv, allAv float64 = 1, 1, ttpb, fork.P9Average
 118  	if lastNode == nil {
 119  		D.Ln("lastNode is nil")
 120  	}
 121  	// algoInterval := fork.P9Algos[algoname].VersionInterval
 122  	startHeight := fork.List[1].ActivationHeight
 123  	if b.params.Net == wire.TestNet3 {
 124  		startHeight = fork.List[1].TestnetStart
 125  	}
 126  	allStamps := GetAllStamps(startHeight, lastNode)
 127  	last, _, algStamps, algoVer := GetAlgStamps(algoName, startHeight, lastNode)
 128  	if len(allStamps) > minAvSamples {
 129  		allAv, allAdj = GetAll(allStamps)
 130  	}
 131  	if len(algStamps) > minAvSamples {
 132  		algAv, algAdj = GetAlg(algStamps, ttpb)
 133  	}
 134  	bits := fork.SecondPowLimitBits
 135  	if last != nil {
 136  		bits = last.bits
 137  	}
 138  	// D.Ln(
 139  	//	"allAv", allAv,
 140  	//	"fork.P9Average", fork.P9Average,
 141  	//	"allAv/fork.P9Average", allAv/fork.P9Average,
 142  	//	"algAv", algAv,
 143  	//	"algAdj", algAdj,
 144  	//	"allAdj", allAdj)
 145  	
 146  	adjustment = algAdj * allAdj
 147  	
 148  	// thisInterval := fork.P9AlgosNumeric[algoVer].VersionInterval
 149  	// baseInterval := fork.P9AlgosNumeric[5].VersionInterval
 150  	// timeFactor := float64(baseInterval) / float64(thisInterval)
 151  	// // if adjustment < 1 {
 152  	// // if the difficulty is adjusting upwards, accelerate it in proportion with block interval's ratio
 153  	// adjustment *= timeFactor
 154  	// // }
 155  	
 156  	// adjustment *= adjustment
 157  	bigAdjustment := big.NewFloat(adjustment)
 158  	bigOldTarget := big.NewFloat(1.0).SetInt(bits2.CompactToBig(bits))
 159  	bigNewTargetFloat := big.NewFloat(1.0).Mul(bigAdjustment, bigOldTarget)
 160  	newTarget, _ := bigNewTargetFloat.Int(nil)
 161  	if newTarget == nil {
 162  		I.Ln("newTarget is nil ")
 163  		return
 164  	}
 165  	if newTarget.Cmp(&fork.FirstPowLimit) < 0 {
 166  		newTargetBits = bits2.BigToCompact(newTarget)
 167  		// Tracef("newTarget %064x %08x", newTarget, newTargetBits)
 168  	}
 169  	// if l {
 170  	// if lastNode.version == algoVer {
 171  	I.Ln(func() string {
 172  		an := fork.List[1].AlgoVers[algoVer]
 173  		pad := 8 - len(an)
 174  		if pad > 0 {
 175  			an += strings.Repeat(" ", pad)
 176  		}
 177  		factor := 1 / adjustment
 178  		symbol := ">"
 179  		if factor < 1 {
 180  			factor = adjustment
 181  			symbol = "<"
 182  		}
 183  		if factor == 1 {
 184  			symbol = "-"
 185  		}
 186  		isNewest := ""
 187  		if lastNode.version == algoVer {
 188  			isNewest = "*"
 189  		}
 190  		return fmt.Sprintf("%s %s av %s/%2.2f %s %s %08x %08x%s",
 191  			an,
 192  			RightJustify(fmt.Sprintf("%4.2f", algAv), 8),
 193  			RightJustify(fmt.Sprintf("%4.2f", allAv), 7),
 194  			fork.P9Average,
 195  			RightJustify(fmt.Sprintf("%4.2f", factor), 7),
 196  			symbol,
 197  			bits,
 198  			newTargetBits,
 199  			isNewest,
 200  		)
 201  	}(),
 202  	)
 203  	// }
 204  	// }
 205  	return
 206  }
 207  
 208  // CalcNextRequiredDifficultyPlan9old calculates the required difficulty for the block after the passed previous block node
 209  // based on the difficulty retarget rules. This function differs from the exported CalcNextRequiredDifficulty in that
 210  // the exported version uses the current best chain as the previous block node while this function accepts any block
 211  // node.
 212  func (b *BlockChain) CalcNextRequiredDifficultyPlan9old(lastNode *BlockNode, algoName string, l bool,
 213  ) (newTargetBits uint32, adjustment float64, e error) {
 214  	
 215  	nH := lastNode.height + 1
 216  	newTargetBits = fork.SecondPowLimitBits
 217  	adjustment = 1.0
 218  	if lastNode == nil || b.IsP9HardFork(nH) {
 219  		return
 220  	}
 221  	allTimeAv, allTimeDiv, qhourDiv, hourDiv,
 222  	dayDiv := b.GetCommonP9Averages(lastNode, nH)
 223  	algoVer := fork.GetAlgoVer(algoName, nH)
 224  	since, ttpb, timeSinceAlgo, startHeight, last := b.GetP9Since(lastNode, algoVer)
 225  	if last == nil {
 226  		return
 227  	}
 228  	algDiv := b.GetP9AlgoDiv(allTimeDiv, last, startHeight, algoVer, ttpb)
 229  	adjustment = (allTimeDiv + algDiv + dayDiv + hourDiv + qhourDiv +
 230  		timeSinceAlgo) / 6
 231  	bigAdjustment := big.NewFloat(adjustment)
 232  	bigOldTarget := big.NewFloat(1.0).SetInt(bits2.CompactToBig(last.bits))
 233  	bigNewTargetFloat := big.NewFloat(1.0).Mul(bigAdjustment, bigOldTarget)
 234  	newTarget, _ := bigNewTargetFloat.Int(nil)
 235  	if newTarget == nil {
 236  		I.Ln("newTarget is nil ")
 237  		return
 238  	}
 239  	if newTarget.Cmp(&fork.FirstPowLimit) < 0 {
 240  		newTargetBits = bits2.BigToCompact(newTarget)
 241  		T.F("newTarget %064x %08x", newTarget, newTargetBits)
 242  	}
 243  	if l {
 244  		an := fork.List[1].AlgoVers[algoVer]
 245  		pad := 9 - len(an)
 246  		if pad > 0 {
 247  			an += strings.Repeat(" ", pad)
 248  		}
 249  		D.C(func() string {
 250  			return fmt.Sprintf("hght: %d %08x %s %s %s %s %s %s %s"+
 251  				" %s %s %08x",
 252  				lastNode.height+1,
 253  				last.bits,
 254  				an,
 255  				RightJustify(fmt.Sprintf("%3.2f", allTimeAv), 5),
 256  				RightJustify(fmt.Sprintf("%3.2fa", allTimeDiv*ttpb), 7),
 257  				RightJustify(fmt.Sprintf("%3.2fd", dayDiv*ttpb), 7),
 258  				RightJustify(fmt.Sprintf("%3.2fh", hourDiv*ttpb), 7),
 259  				RightJustify(fmt.Sprintf("%3.2fq", qhourDiv*ttpb), 7),
 260  				RightJustify(fmt.Sprintf("%3.2fA", algDiv*ttpb), 7),
 261  				RightJustify(fmt.Sprintf("%3.0f %3.3fD",
 262  					since-ttpb*float64(len(fork.List[1].Algos)), timeSinceAlgo*ttpb,
 263  				), 13,
 264  				),
 265  				RightJustify(fmt.Sprintf("%4.4fx", 1/adjustment), 11),
 266  				newTargetBits,
 267  			)
 268  		},
 269  		)
 270  	}
 271  	return
 272  }
 273