Remove github.com/holiman/uint256 dependency on types.DifficultyFromPoW
Implement and compare native P2Pool check_pow use uint128.Max on Difficulty PoW
This commit is contained in:
parent
eb372dc167
commit
44d969a218
2
go.mod
2
go.mod
|
@ -13,8 +13,6 @@ require (
|
|||
github.com/floatdrop/lru v1.3.0
|
||||
github.com/go-zeromq/zmq4 v0.16.0
|
||||
github.com/goccy/go-json v0.10.2
|
||||
github.com/holiman/uint256 v1.2.4
|
||||
github.com/jxskiss/base62 v1.1.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc
|
||||
golang.org/x/sys v0.19.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -27,10 +27,6 @@ github.com/go-zeromq/goczmq/v4 v4.2.2 h1:HAJN+i+3NW55ijMJJhk7oWxHKXgAuSBkoFfvr8b
|
|||
github.com/go-zeromq/goczmq/v4 v4.2.2/go.mod h1:Sm/lxrfxP/Oxqs0tnHD6WAhwkWrx+S+1MRrKzcxoaYE=
|
||||
github.com/go-zeromq/zmq4 v0.16.0 h1:D6oIPWSdkY/4DJu4tBUmo28P3WRq4F4Ji4/iQ/fJHc0=
|
||||
github.com/go-zeromq/zmq4 v0.16.0/go.mod h1:8c3aXloJBRPba1AqWMJK4vypniM+yC+JKqi8KpRaDFc=
|
||||
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw=
|
||||
github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"git.gammaspectra.live/P2Pool/consensus/v3/utils"
|
||||
"github.com/holiman/uint256"
|
||||
fasthex "github.com/tmthrgd/go-hex"
|
||||
"io"
|
||||
"lukechampine.com/uint128"
|
||||
|
@ -327,44 +325,3 @@ func (d *Difficulty) Scan(src any) error {
|
|||
func (d *Difficulty) Value() (driver.Value, error) {
|
||||
return d.Bytes(), nil
|
||||
}
|
||||
|
||||
// TODO: remove uint256 dependency as it's unique to this section
|
||||
var powBase = uint256.NewInt(0).SetBytes32(bytes.Repeat([]byte{0xff}, 32))
|
||||
|
||||
func DifficultyFromPoW(powHash Hash) Difficulty {
|
||||
if powHash == ZeroHash {
|
||||
return ZeroDifficulty
|
||||
}
|
||||
|
||||
pow := uint256.NewInt(0).SetBytes32(powHash[:])
|
||||
pow = &uint256.Int{bits.ReverseBytes64(pow[3]), bits.ReverseBytes64(pow[2]), bits.ReverseBytes64(pow[1]), bits.ReverseBytes64(pow[0])}
|
||||
|
||||
powResult := uint256.NewInt(0).Div(powBase, pow).Bytes32()
|
||||
return DifficultyFromBytes(powResult[16:])
|
||||
}
|
||||
|
||||
func (d Difficulty) CheckPoW(pow Hash) bool {
|
||||
return DifficultyFromPoW(pow).Cmp(d) >= 0
|
||||
}
|
||||
|
||||
// Target
|
||||
// Finds a 64-bit target for mining (target = 2^64 / difficulty) and rounds up the result of division
|
||||
// Because of that, there's a very small chance that miners will find a hash that meets the target but is still wrong (hash * difficulty >= 2^256)
|
||||
// A proper difficulty check is in check_pow()
|
||||
func (d Difficulty) Target() uint64 {
|
||||
if d.Hi > 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Safeguard against division by zero (CPU will trigger it even if lo = 1 because result doesn't fit in 64 bits)
|
||||
if d.Lo <= 1 {
|
||||
return math.MaxUint64
|
||||
}
|
||||
|
||||
q, rem := Difficulty{Hi: 1, Lo: 0}.QuoRem64(d.Lo)
|
||||
if rem > 0 {
|
||||
return q.Lo + 1
|
||||
} else {
|
||||
return q.Lo
|
||||
}
|
||||
}
|
||||
|
|
89
types/pow.go
Normal file
89
types/pow.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"lukechampine.com/uint128"
|
||||
"math"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
func DifficultyFromPoW(powHash Hash) Difficulty {
|
||||
if powHash == ZeroHash {
|
||||
return ZeroDifficulty
|
||||
}
|
||||
|
||||
return Difficulty(uint128.Max.Div(uint128.FromBytes(powHash[16:])))
|
||||
}
|
||||
|
||||
func (d Difficulty) CheckPoW(pow Hash) bool {
|
||||
return DifficultyFromPoW(pow).Cmp(d) >= 0
|
||||
}
|
||||
|
||||
func (d Difficulty) CheckPoW_Native(pow Hash) bool {
|
||||
// P2Pool similar code
|
||||
var result [6]uint64
|
||||
var product [6]uint64
|
||||
|
||||
a := [4]uint64{
|
||||
binary.LittleEndian.Uint64(pow[:]),
|
||||
binary.LittleEndian.Uint64(pow[8:]),
|
||||
binary.LittleEndian.Uint64(pow[16:]),
|
||||
binary.LittleEndian.Uint64(pow[24:]),
|
||||
}
|
||||
|
||||
if d.Hi == 0 {
|
||||
for i := 3; i >= 0; i-- {
|
||||
product[1], product[0] = bits.Mul64(a[i], d.Lo)
|
||||
|
||||
var carry uint64
|
||||
for k, l := i, 0; k < 5; k, l = k+1, l+1 {
|
||||
result[k], carry = bits.Add64(result[k], product[l], carry)
|
||||
}
|
||||
|
||||
if result[4] > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
b := [2]uint64{d.Lo, d.Hi}
|
||||
|
||||
for i := 3; i >= 0; i-- {
|
||||
for j := 1; j >= 0; j-- {
|
||||
product[1], product[0] = bits.Mul64(a[i], b[j])
|
||||
|
||||
var carry uint64
|
||||
for k, l := i+j, 0; k < 6; k, l = k+1, l+1 {
|
||||
result[k], carry = bits.Add64(result[k], product[l], carry)
|
||||
}
|
||||
|
||||
if result[4] > 0 || result[5] > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Target
|
||||
// Finds a 64-bit target for mining (target = 2^64 / difficulty) and rounds up the result of division
|
||||
// Because of that, there's a very small chance that miners will find a hash that meets the target but is still wrong (hash * difficulty >= 2^256)
|
||||
// A proper difficulty check is in check_pow()
|
||||
func (d Difficulty) Target() uint64 {
|
||||
if d.Hi > 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Safeguard against division by zero (CPU will trigger it even if lo = 1 because result doesn't fit in 64 bits)
|
||||
if d.Lo <= 1 {
|
||||
return math.MaxUint64
|
||||
}
|
||||
|
||||
q, rem := Difficulty{Hi: 1, Lo: 0}.QuoRem64(d.Lo)
|
||||
if rem > 0 {
|
||||
return q.Lo + 1
|
||||
} else {
|
||||
return q.Lo
|
||||
}
|
||||
}
|
78
types/pow_test.go
Normal file
78
types/pow_test.go
Normal file
|
@ -0,0 +1,78 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
powHash = MustHashFromString("abcf2c2ee4a64a683f24bedb2099dd16ae08c03a1ecc1208bf93a90200000000")
|
||||
sidechainDifficulty = DifficultyFrom64(2062136440)
|
||||
powDifficulty = DifficultyFrom64(412975968250)
|
||||
moneroDifficulty = DifficultyFrom64(229654626174)
|
||||
)
|
||||
|
||||
func TestDifficultyFromPoW(t *testing.T) {
|
||||
diff := DifficultyFromPoW(powHash)
|
||||
|
||||
if !diff.Equals(powDifficulty) {
|
||||
t.Errorf("%s does not equal %s", diff, powDifficulty)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDifficulty_CheckPoW(t *testing.T) {
|
||||
|
||||
if !moneroDifficulty.CheckPoW(powHash) {
|
||||
t.Errorf("%s does not pass PoW %s", powHash, moneroDifficulty)
|
||||
}
|
||||
|
||||
if !sidechainDifficulty.CheckPoW(powHash) {
|
||||
t.Errorf("%s does not pass PoW %s", powHash, sidechainDifficulty)
|
||||
}
|
||||
|
||||
if !powDifficulty.CheckPoW(powHash) {
|
||||
t.Errorf("%s does not pass PoW %s", powHash, powDifficulty)
|
||||
}
|
||||
|
||||
powHash2 := powHash
|
||||
powHash2[len(powHash2)-1]++
|
||||
|
||||
if moneroDifficulty.CheckPoW(powHash2) {
|
||||
t.Errorf("%s does pass PoW %s incorrectly", powHash2, moneroDifficulty)
|
||||
}
|
||||
|
||||
if sidechainDifficulty.CheckPoW(powHash2) {
|
||||
t.Errorf("%s does pass PoW %s incorrectly", powHash2, sidechainDifficulty)
|
||||
}
|
||||
|
||||
powHash3 := powHash
|
||||
powHash3[len(powHash2)-9]++
|
||||
|
||||
if powDifficulty.CheckPoW(powHash3) {
|
||||
t.Errorf("%s does pass PoW %s incorrectly", powHash3, powDifficulty)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDifficulty_CheckPoW(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
var result bool
|
||||
for pb.Next() {
|
||||
result = moneroDifficulty.CheckPoW(powHash)
|
||||
}
|
||||
runtime.KeepAlive(result)
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDifficulty_CheckPoW_Native(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
var result bool
|
||||
for pb.Next() {
|
||||
result = moneroDifficulty.CheckPoW_Native(powHash)
|
||||
}
|
||||
runtime.KeepAlive(result)
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue