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.

140 lines
4.9 KiB

  1. // Copyright 2017-2018 DERO Project. All rights reserved.
  2. // Use of this source code in any form is governed by RESEARCH license.
  3. // license can be found in the LICENSE file.
  4. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
  5. //
  6. //
  7. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  8. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  10. // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  14. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. package difficulty
  17. import "fmt"
  18. import "math/big"
  19. import "github.com/arnaucode/derosuite/config"
  20. import "github.com/arnaucode/derosuite/crypto"
  21. var (
  22. // bigZero is 0 represented as a big.Int. It is defined here to avoid
  23. // the overhead of creating it multiple times.
  24. bigZero = big.NewInt(0)
  25. // bigOne is 1 represented as a big.Int. It is defined here to avoid
  26. // the overhead of creating it multiple times.
  27. bigOne = big.NewInt(1)
  28. // oneLsh256 is 1 shifted left 256 bits. It is defined here to avoid
  29. // the overhead of creating it multiple times.
  30. oneLsh256 = new(big.Int).Lsh(bigOne, 256)
  31. // enabling this will simulation mode with hard coded difficulty set to 1
  32. // the variable is knowingly not exported, so no one can tinker with it
  33. simulation = false // simulation mode is disabled
  34. )
  35. // HashToBig converts a PoW has into a big.Int that can be used to
  36. // perform math comparisons.
  37. func HashToBig(buf crypto.Hash) *big.Int {
  38. // A Hash is in little-endian, but the big package wants the bytes in
  39. // big-endian, so reverse them.
  40. blen := len(buf) // its hardcoded 32 bytes, so why do len but lets do it
  41. for i := 0; i < blen/2; i++ {
  42. buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
  43. }
  44. return new(big.Int).SetBytes(buf[:])
  45. }
  46. // this function calculates the difficulty in big num form
  47. func ConvertDifficultyToBig(difficultyi uint64) *big.Int {
  48. if difficultyi == 0 {
  49. panic("difficulty can never be zero")
  50. }
  51. // (1 << 256) / (difficultyNum )
  52. difficulty := new(big.Int).SetUint64(difficultyi)
  53. denominator := new(big.Int).Add(difficulty, bigZero) // above 2 lines can be merged
  54. return new(big.Int).Div(oneLsh256, denominator)
  55. }
  56. // this function check whether the pow hash meets difficulty criteria
  57. func CheckPowHash(pow_hash crypto.Hash, difficulty uint64) bool {
  58. big_difficulty := ConvertDifficultyToBig(difficulty)
  59. big_pow_hash := HashToBig(pow_hash)
  60. if big_pow_hash.Cmp(big_difficulty) <= 0 { // if work_pow is less than difficulty
  61. return true
  62. }
  63. return false
  64. }
  65. /* this function calculates difficulty on the basis of previous timestamps and cumulative_difficulty */
  66. func Next_Difficulty(timestamps []uint64, cumulative_difficulty []uint64, target_seconds uint64) (difficulty uint64) {
  67. difficulty = 1 // default difficulty is 1 // for genesis block
  68. if simulation == true { // simulation mode has difficulty set to 1
  69. return 1
  70. }
  71. if len(timestamps) > config.DIFFICULTY_BLOCKS_COUNT_V2 {
  72. panic("More timestamps provided than required")
  73. }
  74. if len(timestamps) != len(cumulative_difficulty) {
  75. panic("Number of timestamps != Number of cumulative_difficulty")
  76. }
  77. if len(timestamps) <= 1 {
  78. return difficulty // return 1
  79. }
  80. length := uint64(len(timestamps))
  81. weighted_timespans := uint64(0)
  82. for i := uint64(1); i < length; i++ {
  83. timespan := uint64(0)
  84. if timestamps[i-1] >= timestamps[i] {
  85. timespan = 1
  86. } else {
  87. timespan = timestamps[i] - timestamps[i-1]
  88. }
  89. if timespan > (10 * target_seconds) {
  90. timespan = 10 * target_seconds
  91. }
  92. weighted_timespans += i * timespan
  93. }
  94. minimum_timespan := (target_seconds * length) / 2
  95. if weighted_timespans < minimum_timespan { // fix startup weirdness
  96. weighted_timespans = minimum_timespan
  97. }
  98. total_work := cumulative_difficulty[length-1] - cumulative_difficulty[0]
  99. // convert input for 128 bit multiply
  100. var big_total_work, big_target, big_result big.Int
  101. big_total_work.SetUint64(total_work)
  102. target := (((length + 1) / 2) * target_seconds * 3) / 2
  103. big_target.SetUint64(target)
  104. big_result.Mul(&big_total_work, &big_target)
  105. if big_result.IsUint64() {
  106. if big_result.Uint64() > 0x000fffffffffffff { // this will give us atleast 1 year to fix the difficulty algorithm
  107. fmt.Printf("Total work per target_time will soon cross 2^64, please fix the difficulty algorithm\n")
  108. }
  109. difficulty = big_result.Uint64() / weighted_timespans
  110. } else {
  111. panic("Total work per target_time crossing 2^64 , please fix the above")
  112. }
  113. return difficulty
  114. }