| 427 | } |
| 428 | |
| 429 | func (pow *Full) Search(block pow.Block, stop <-chan struct{}, index int) (nonce uint64, mixDigest []byte) { |
| 430 | dag := pow.getDAG(block.NumberU64()) |
| 431 | |
| 432 | r := rand.New(rand.NewSource(time.Now().UnixNano())) |
| 433 | diff := block.Difficulty() |
| 434 | |
| 435 | i := int64(0) |
| 436 | starti := i |
| 437 | start := time.Now().UnixNano() |
| 438 | previousHashrate := int32(0) |
| 439 | |
| 440 | nonce = uint64(r.Int63()) |
| 441 | hash := hashToH256(block.HashNoNonce()) |
| 442 | target := new(big.Int).Div(maxUint256, diff) |
| 443 | for { |
| 444 | select { |
| 445 | case <-stop: |
| 446 | atomic.AddInt32(&pow.hashRate, -previousHashrate) |
| 447 | return 0, nil |
| 448 | default: |
| 449 | i++ |
| 450 | |
| 451 | // we don't have to update hash rate on every nonce, so update after |
| 452 | // first nonce check and then after 2^X nonces |
| 453 | if i == 2 || ((i % (1 << 16)) == 0) { |
| 454 | elapsed := time.Now().UnixNano() - start |
| 455 | hashes := (float64(1e9) / float64(elapsed)) * float64(i-starti) |
| 456 | hashrateDiff := int32(hashes) - previousHashrate |
| 457 | previousHashrate = int32(hashes) |
| 458 | atomic.AddInt32(&pow.hashRate, hashrateDiff) |
| 459 | } |
| 460 | |
| 461 | ret := C.ethash_full_compute(dag.ptr, hash, C.uint64_t(nonce)) |
| 462 | result := h256ToHash(ret.result).Big() |
| 463 | |
| 464 | // TODO: disagrees with the spec https://gopkg.in/ethereum/wiki/wiki/Ethash#mining |
| 465 | if ret.success && result.Cmp(target) <= 0 { |
| 466 | mixDigest = C.GoBytes(unsafe.Pointer(&ret.mix_hash), C.int(32)) |
| 467 | atomic.AddInt32(&pow.hashRate, -previousHashrate) |
| 468 | return nonce, mixDigest |
| 469 | } |
| 470 | nonce += 1 |
| 471 | } |
| 472 | |
| 473 | if !pow.turbo { |
| 474 | time.Sleep(20 * time.Microsecond) |
| 475 | } |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | func (pow *Full) GetHashrate() int64 { |
| 480 | return int64(atomic.LoadInt32(&pow.hashRate)) |