You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
3.6 KiB

  1. package difficulty
  2. import "fmt"
  3. import "math/big"
  4. import "github.com/deroproject/derosuite/config"
  5. import "github.com/deroproject/derosuite/crypto"
  6. var (
  7. // bigZero is 0 represented as a big.Int. It is defined here to avoid
  8. // the overhead of creating it multiple times.
  9. bigZero = big.NewInt(0)
  10. // bigOne is 1 represented as a big.Int. It is defined here to avoid
  11. // the overhead of creating it multiple times.
  12. bigOne = big.NewInt(1)
  13. // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid
  14. // the overhead of creating it multiple times.
  15. oneLsh256 = new(big.Int).Lsh(bigOne, 256)
  16. )
  17. // HashToBig converts a PoW has into a big.Int that can be used to
  18. // perform math comparisons.
  19. func HashToBig(buf crypto.Hash) *big.Int {
  20. // A Hash is in little-endian, but the big package wants the bytes in
  21. // big-endian, so reverse them.
  22. blen := len(buf) // its hardcoded 32 bytes, so why do len but lets do it
  23. for i := 0; i < blen/2; i++ {
  24. buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
  25. }
  26. return new(big.Int).SetBytes(buf[:])
  27. }
  28. // this function calculates the difficulty in big num form
  29. func ConvertDifficultyToBig(difficultyi uint64) *big.Int {
  30. if difficultyi == 0 {
  31. panic("difficulty can never be zero")
  32. }
  33. // (1 << 256) / (difficultyNum )
  34. difficulty := new(big.Int).SetUint64(difficultyi)
  35. denominator := new(big.Int).Add(difficulty, bigZero) // above 2 lines can be merged
  36. return new(big.Int).Div(oneLsh256, denominator)
  37. }
  38. // this function check whether the pow hash meets difficulty criteria
  39. func CheckPowHash(pow_hash crypto.Hash, difficulty uint64) bool {
  40. big_difficulty := ConvertDifficultyToBig(difficulty)
  41. big_pow_hash := HashToBig(pow_hash)
  42. if big_pow_hash.Cmp(big_difficulty) <= 0 { // if work_pow is less than difficulty
  43. return true
  44. }
  45. return false
  46. }
  47. /* this function calculates difficulty on the basis of previous timestamps and cumulative_difficulty */
  48. func Next_Difficulty(timestamps []uint64, cumulative_difficulty []uint64, target_seconds uint64) (difficulty uint64) {
  49. difficulty = 1 // default difficulty is 1 // for genesis block
  50. if len(timestamps) > config.DIFFICULTY_BLOCKS_COUNT_V2 {
  51. panic("More timestamps provided than required")
  52. }
  53. if len(timestamps) != len(cumulative_difficulty) {
  54. panic("Number of timestamps != Number of cumulative_difficulty")
  55. }
  56. if len(timestamps) <= 1 {
  57. return difficulty // return 1
  58. }
  59. length := uint64(len(timestamps))
  60. weighted_timespans := uint64(0)
  61. for i := uint64(1); i < length; i++ {
  62. timespan := uint64(0)
  63. if timestamps[i-1] >= timestamps[i] {
  64. timespan = 1
  65. } else {
  66. timespan = timestamps[i] - timestamps[i-1]
  67. }
  68. if timespan > (10 * target_seconds) {
  69. timespan = 10 * target_seconds
  70. }
  71. weighted_timespans += i * timespan
  72. }
  73. minimum_timespan := (target_seconds * length) / 2
  74. if weighted_timespans < minimum_timespan { // fix startup weirdness
  75. weighted_timespans = minimum_timespan
  76. }
  77. total_work := cumulative_difficulty[length-1] - cumulative_difficulty[0]
  78. // convert input for 128 bit multiply
  79. var big_total_work, big_target, big_result big.Int
  80. big_total_work.SetUint64(total_work)
  81. target := (((length + 1) / 2) * target_seconds * 3) / 2
  82. big_target.SetUint64(target)
  83. big_result.Mul(&big_total_work, &big_target)
  84. if big_result.IsUint64() {
  85. if big_result.Uint64() > 0x000fffffffffffff { // this will give us atleast 1 year to fix the difficulty algorithm
  86. fmt.Printf("Total work per target_time will soon cross 2^64, please fix the difficulty algorithm\n")
  87. }
  88. difficulty = big_result.Uint64() / weighted_timespans
  89. } else {
  90. panic("Total work per target_time crossing 2^64 , please fix the above")
  91. }
  92. return difficulty
  93. }