diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go | 215 |
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 } |