-
Notifications
You must be signed in to change notification settings - Fork 7
/
pow.go
63 lines (49 loc) · 1.5 KB
/
pow.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package ProofWork
import (
"encoding/binary"
"runtime"
"golang.org/x/crypto/blake2b"
)
var MinimumWork = uint64(0xffffffc000000000)
// GenerateProof will generate the proof of work, the nonce itself is one uint64 in BigEndian, it's generate as follows:
// Pick one unique Nonce and concatenate with the Blockhash:
// [LittleEndian UINT64 Nonce][BlockHash]
// Now computes the hash of the previous concatenation:
// Blake2(size = 8, message = [LittleEndian UINT64 Nonce][BlockHash])
// Now you need to use this value as one UINT64 and compare against the minimum work:
// LitleEndian(Blake2(...)) > MinimumWork
// If it's correct then you have in hand one correct nonce/pow, you need to reverse it so use the BigEndian.
func GenerateProof(blockHash []byte) []byte {
limit := uint64(runtime.NumCPU())
shard := uint64(1<<64-1) / limit
result := make(chan uint64)
stop := make(chan bool)
for i := uint64(0); i < limit; i++ {
go createProof(blockHash, i*shard, result, stop)
}
nonce := <-result
close(stop)
close(result)
n := make([]byte, 8)
binary.BigEndian.PutUint64(n, nonce)
return n
}
func createProof(blockHash []byte, attempt uint64, result chan uint64, stop chan bool) {
h, _ := blake2b.New(8, nil)
nonce := make([]byte, 40)
copy(nonce[8:], blockHash)
for {
select {
default:
binary.LittleEndian.PutUint64(nonce[:8], attempt)
h.Reset()
h.Write(nonce)
if binary.LittleEndian.Uint64(h.Sum(nil)) >= MinimumWork {
result <- attempt
}
attempt++
case <-stop:
return
}
}
}