aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go')
-rw-r--r--Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go215
1 files changed, 136 insertions, 79 deletions
diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
index 32d3f0264..e50a3a834 100644
--- a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
+++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go
@@ -2,32 +2,39 @@ package ethash
/*
#cgo CFLAGS: -std=gnu99 -Wall
-#include "libethash/ethash.h"
-#include "libethash/util.c"
-#include "libethash/internal.c"
-#include "libethash/sha3.c"
+#include "src/libethash/util.c"
+#include "src/libethash/internal.c"
+#include "src/libethash/sha3.c"
*/
import "C"
import (
"bytes"
"encoding/binary"
+ "fmt"
+ "io/ioutil"
"log"
"math/big"
"math/rand"
+ "os"
+ "path"
"sync"
"time"
"unsafe"
+ "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
)
+var tt256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
+
var powlogger = logger.NewLogger("POW")
type DAG struct {
SeedBlockNum uint64
dag unsafe.Pointer // full GB of memory for dag
+ file bool
}
type ParamsAndCache struct {
@@ -59,16 +66,28 @@ func parseNonce(nonce []byte) (uint64, error) {
const epochLength uint64 = 30000
-func getSeedBlockNum(blockNum uint64) uint64 {
+func GetSeedBlockNum(blockNum uint64) uint64 {
+ var seedBlockNum uint64 = 0
+ if blockNum > epochLength {
+ seedBlockNum = ((blockNum - 1) / epochLength) * epochLength
+ }
+ return seedBlockNum
+}
+
+/*
+XXX THIS DOESN'T WORK!! NEEDS FIXING
+blockEpoch will underflow and wrap around causing massive issues
+func GetSeedBlockNum(blockNum uint64) uint64 {
var seedBlockNum uint64 = 0
- if blockNum >= 2*epochLength {
- seedBlockNum = ((blockNum / epochLength) - 1) * epochLength
+ if blockNum > epochLength {
+ seedBlockNum = ((blockNum - 1) / epochLength) * epochLength
}
return seedBlockNum
}
+*/
func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) *ParamsAndCache {
- seedBlockNum := getSeedBlockNum(blockNum)
+ seedBlockNum := GetSeedBlockNum(blockNum)
paramsAndCache := &ParamsAndCache{
params: new(C.ethash_params),
cache: new(C.ethash_cache),
@@ -76,19 +95,19 @@ func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) *ParamsA
}
C.ethash_params_init(paramsAndCache.params, C.uint32_t(seedBlockNum))
paramsAndCache.cache.mem = C.malloc(paramsAndCache.params.cache_size)
- seedHash := chainManager.GetBlockByNumber(seedBlockNum).Header().Hash()
- log.Println("Params", paramsAndCache.params)
+ seedHash := chainManager.GetBlockByNumber(seedBlockNum).SeedHash()
log.Println("Making Cache")
start := time.Now()
- C.ethash_mkcache(paramsAndCache.cache, paramsAndCache.params, (*C.uint8_t)((unsafe.Pointer)(&seedHash[0])))
+ C.ethash_mkcache(paramsAndCache.cache, paramsAndCache.params, (*C.uint8_t)(unsafe.Pointer(&seedHash[0])))
log.Println("Took:", time.Since(start))
+
return paramsAndCache
}
func (pow *Ethash) updateCache() {
pow.cacheMutex.Lock()
- seedNum := getSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64())
+ seedNum := GetSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64())
if pow.paramsAndCache.SeedBlockNum != seedNum {
pow.paramsAndCache = makeParamsAndCache(pow.chainManager, pow.chainManager.CurrentBlock().NumberU64())
}
@@ -104,17 +123,66 @@ func makeDAG(p *ParamsAndCache) *DAG {
return d
}
-func (pow *Ethash) updateDAG() {
+func (pow *Ethash) writeDagToDisk(dag *DAG, seedNum uint64) *os.File {
+ data := C.GoBytes(unsafe.Pointer(dag.dag), C.int(pow.paramsAndCache.params.full_size))
+ file, err := os.Create("/tmp/dag")
+ if err != nil {
+ panic(err)
+ }
+
+ num := make([]byte, 8)
+ binary.BigEndian.PutUint64(num, seedNum)
+
+ file.Write(num)
+ file.Write(data)
+
+ return file
+}
+
+func (pow *Ethash) UpdateDAG() {
pow.cacheMutex.Lock()
pow.dagMutex.Lock()
- seedNum := getSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64())
+ seedNum := GetSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64())
if pow.dag == nil || pow.dag.SeedBlockNum != seedNum {
+ if pow.dag != nil && pow.dag.dag != nil {
+ C.free(pow.dag.dag)
+ pow.dag.dag = nil
+ }
+
+ path := path.Join("/", "tmp", "dag")
pow.dag = nil
- log.Println("Making Dag")
+ log.Println("Generating dag")
start := time.Now()
- pow.dag = makeDAG(pow.paramsAndCache)
+
+ file, err := os.Open(path)
+ if err != nil {
+ log.Printf("No dag found in '%s'. Generating new dago(takes a while)...", path)
+ pow.dag = makeDAG(pow.paramsAndCache)
+ file = pow.writeDagToDisk(pow.dag, seedNum)
+ } else {
+ data, err := ioutil.ReadAll(file)
+ if err != nil {
+ panic(err)
+ }
+
+ num := binary.BigEndian.Uint64(data[0:8])
+ if num < seedNum {
+ log.Printf("Old found. Generating new dag (takes a while)...")
+ pow.dag = makeDAG(pow.paramsAndCache)
+ file = pow.writeDagToDisk(pow.dag, seedNum)
+ } else {
+ data = data[8:]
+ pow.dag = &DAG{
+ dag: unsafe.Pointer(&data[0]),
+ file: true,
+ SeedBlockNum: pow.paramsAndCache.SeedBlockNum,
+ }
+ }
+ }
log.Println("Took:", time.Since(start))
+
+ file.Close()
}
pow.dagMutex.Unlock()
@@ -123,11 +191,10 @@ func (pow *Ethash) updateDAG() {
func New(chainManager pow.ChainManager) *Ethash {
return &Ethash{
- turbo: false,
+ turbo: true,
paramsAndCache: makeParamsAndCache(chainManager, chainManager.CurrentBlock().NumberU64()),
chainManager: chainManager,
dag: nil,
- ret: new(C.ethash_return_value),
cacheMutex: new(sync.Mutex),
dagMutex: new(sync.Mutex),
}
@@ -142,73 +209,70 @@ func (pow *Ethash) CacheSize() uint64 {
}
func (pow *Ethash) GetSeedHash(blockNum uint64) []byte {
- return pow.chainManager.GetBlockByNumber(getSeedBlockNum(blockNum)).Header().Hash()
+ seednum := GetSeedBlockNum(blockNum)
+ return pow.chainManager.GetBlockByNumber(seednum).SeedHash()
}
func (pow *Ethash) Stop() {
pow.cacheMutex.Lock()
pow.dagMutex.Lock()
+ defer pow.dagMutex.Unlock()
+ defer pow.cacheMutex.Unlock()
+
if pow.paramsAndCache.cache != nil {
C.free(pow.paramsAndCache.cache.mem)
}
- if pow.dag != nil {
+ if pow.dag.dag != nil && !pow.dag.file {
C.free(pow.dag.dag)
}
- pow.dagMutex.Unlock()
- pow.cacheMutex.Unlock()
+ pow.dag.dag = nil
}
-func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) ([]byte, []byte, []byte) {
- pow.updateDAG()
+func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte, []byte) {
+ //pow.UpdateDAG()
// Not very elegant, multiple mining instances are not supported
- pow.dagMutex.Lock()
- pow.cacheMutex.Lock()
- defer pow.cacheMutex.Unlock()
- defer pow.dagMutex.Unlock()
+ //pow.dagMutex.Lock()
+ //pow.cacheMutex.Lock()
+ //defer pow.cacheMutex.Unlock()
+ //defer pow.dagMutex.Unlock()
r := rand.New(rand.NewSource(time.Now().UnixNano()))
miningHash := block.HashNoNonce()
diff := block.Difficulty()
- log.Println("difficulty", diff)
+
i := int64(0)
+ starti := i
start := time.Now().UnixNano()
- t := time.Now()
nonce := uint64(r.Int63())
+ cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0]))
+ target := new(big.Int).Div(tt256, diff)
+ var ret C.ethash_return_value
for {
select {
case <-stop:
powlogger.Infoln("Breaking from mining")
pow.HashRate = 0
- pow.dagMutex.Unlock()
- return nil, nil, nil
+ return 0, nil, nil
default:
i++
- if time.Since(t) > (1 * time.Second) {
- elapsed := time.Now().UnixNano() - start
- hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000
- pow.HashRate = int64(hashes)
- powlogger.Infoln("Hashing @", pow.HashRate, "khash")
+ elapsed := time.Now().UnixNano() - start
+ hashes := ((float64(1e9) / float64(elapsed)) * float64(i-starti)) / 1000
+ pow.HashRate = int64(hashes)
- t = time.Now()
- }
+ C.ethash_full(&ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, C.uint64_t(nonce))
+ result := ethutil.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32)))
+
+ if result.Cmp(target) <= 0 {
+ mixDigest := C.GoBytes(unsafe.Pointer(&ret.mix_hash[0]), C.int(32))
+
+ return nonce, mixDigest, pow.GetSeedHash(block.NumberU64())
- cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash))
- cnonce := C.uint64_t(nonce)
- log.Printf("seed hash, nonce: %x %x\n", miningHash, nonce)
- // pow.hash is the output/return of ethash_full
- C.ethash_full(pow.ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, cnonce)
- res := C.ethash_check_difficulty((*C.uint8_t)(&pow.ret.result[0]), (*C.uint8_t)(unsafe.Pointer(&diff.Bytes()[0])))
- if res == 1 {
- mixDigest := C.GoBytes(unsafe.Pointer(&pow.ret.mix_hash[0]), 32)
- // We don't really nead 32 bytes here
- buf := make([]byte, 32)
- binary.PutUvarint(buf, nonce)
- return buf, mixDigest, pow.GetSeedHash(block.NumberU64())
}
+
nonce += 1
}
@@ -216,43 +280,32 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) ([]byte, []byte
time.Sleep(20 * time.Microsecond)
}
}
+
}
func (pow *Ethash) Verify(block pow.Block) bool {
// Make sure the SeedHash is set correctly
if bytes.Compare(block.SeedHash(), pow.GetSeedHash(block.NumberU64())) != 0 {
- log.Println("Block had wrong SeedHash")
- log.Println("Expected: ", pow.GetSeedHash(block.NumberU64()))
- log.Println("Actual: ", block.SeedHash())
return false
}
- nonceInt, err := parseNonce(block.Nonce())
- if err != nil {
- log.Println("nonce to int err:", err)
- return false
- }
- return pow.verify(block.HashNoNonce(), block.MixDigest(), block.Difficulty(), block.NumberU64(), nonceInt)
+ return pow.verify(block.HashNoNonce(), block.MixDigest(), block.Difficulty(), block.NumberU64(), block.Nonce())
}
func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, blockNum uint64, nonce uint64) bool {
+ fmt.Printf("%x\n%d\n%x\n%x\n", hash, nonce, mixDigest, difficulty.Bytes())
// First check: make sure header, mixDigest, nonce are correct without hitting the DAG
// This is to prevent DOS attacks
- chash := (*C.uint8_t)(unsafe.Pointer(&hash))
+ chash := (*C.uint8_t)(unsafe.Pointer(&hash[0]))
cnonce := C.uint64_t(nonce)
- cmixDigest := (*C.uint8_t)(unsafe.Pointer(&mixDigest))
- cdifficulty := (*C.uint8_t)(unsafe.Pointer(&difficulty.Bytes()[0]))
- if C.ethash_quick_check_difficulty(chash, cnonce, cmixDigest, cdifficulty) != 1 {
- log.Println("Failed to pass quick check. Are you sure that the mix digest is correct?")
- return false
- }
+ target := new(big.Int).Div(tt256, difficulty)
var pAc *ParamsAndCache
// If its an old block (doesn't use the current cache)
// get the cache for it but don't update (so we don't need the mutex)
// Otherwise, it's the current block or a future.
// If current, updateCache will do nothing.
- if getSeedBlockNum(blockNum) < pow.paramsAndCache.SeedBlockNum {
+ if GetSeedBlockNum(blockNum) < pow.paramsAndCache.SeedBlockNum {
pAc = makeParamsAndCache(pow.chainManager, blockNum)
} else {
pow.updateCache()
@@ -261,9 +314,12 @@ func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, bl
pAc = pow.paramsAndCache
}
- C.ethash_light(pow.ret, pAc.cache, pAc.params, chash, cnonce)
- res := C.ethash_check_difficulty((*C.uint8_t)(unsafe.Pointer(&pow.ret.result[0])), cdifficulty)
- return res == 1
+ ret := new(C.ethash_return_value)
+
+ C.ethash_light(ret, pAc.cache, pAc.params, chash, cnonce)
+
+ result := ethutil.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32)))
+ return result.Cmp(target) <= 0
}
func (pow *Ethash) GetHashrate() int64 {
@@ -275,22 +331,23 @@ func (pow *Ethash) Turbo(on bool) {
}
func (pow *Ethash) FullHash(nonce uint64, miningHash []byte) []byte {
- pow.updateDAG()
+ pow.UpdateDAG()
pow.dagMutex.Lock()
defer pow.dagMutex.Unlock()
- cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash))
+ cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0]))
cnonce := C.uint64_t(nonce)
- log.Println("seed hash, nonce:", miningHash, nonce)
+ ret := new(C.ethash_return_value)
// pow.hash is the output/return of ethash_full
- C.ethash_full(pow.ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, cnonce)
- ghash_full := C.GoBytes(unsafe.Pointer(&pow.ret.result[0]), 32)
+ C.ethash_full(ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, cnonce)
+ ghash_full := C.GoBytes(unsafe.Pointer(&ret.result), 32)
return ghash_full
}
func (pow *Ethash) LightHash(nonce uint64, miningHash []byte) []byte {
- cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash))
+ cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0]))
cnonce := C.uint64_t(nonce)
- C.ethash_light(pow.ret, pow.paramsAndCache.cache, pow.paramsAndCache.params, cMiningHash, cnonce)
- ghash_light := C.GoBytes(unsafe.Pointer(&pow.ret.result[0]), 32)
+ ret := new(C.ethash_return_value)
+ C.ethash_light(ret, pow.paramsAndCache.cache, pow.paramsAndCache.params, cMiningHash, cnonce)
+ ghash_light := C.GoBytes(unsafe.Pointer(&ret.result), 32)
return ghash_light
}