pow: fix Search with ethash test mode
The cache/dataset methods crashed with a nil pointer error if cachesinmem/dagsinmem were zero. Fix it by skipping the eviction logic if there are no caches/datasets. Search always used the regular dataset size regardless of test mode. Fix it by removing the redundant size parameter of hashimotoFull. Fixes #3784
This commit is contained in:
		@@ -428,7 +428,7 @@ func (ethash *Ethash) cache(block uint64) []uint32 {
 | 
			
		||||
	current, future := ethash.caches[epoch], (*cache)(nil)
 | 
			
		||||
	if current == nil {
 | 
			
		||||
		// No in-memory cache, evict the oldest if the cache limit was reached
 | 
			
		||||
		for len(ethash.caches) >= ethash.cachesinmem {
 | 
			
		||||
		for len(ethash.caches) > 0 && len(ethash.caches) >= ethash.cachesinmem {
 | 
			
		||||
			var evict *cache
 | 
			
		||||
			for _, cache := range ethash.caches {
 | 
			
		||||
				if evict == nil || evict.used.After(cache.used) {
 | 
			
		||||
@@ -480,22 +480,16 @@ func (ethash *Ethash) cache(block uint64) []uint32 {
 | 
			
		||||
// Search implements PoW, attempting to find a nonce that satisfies the block's
 | 
			
		||||
// difficulty requirements.
 | 
			
		||||
func (ethash *Ethash) Search(block Block, stop <-chan struct{}) (uint64, []byte) {
 | 
			
		||||
	// Extract some data from the block
 | 
			
		||||
	var (
 | 
			
		||||
		hash   = block.HashNoNonce().Bytes()
 | 
			
		||||
		diff   = block.Difficulty()
 | 
			
		||||
		target = new(big.Int).Div(maxUint256, diff)
 | 
			
		||||
	)
 | 
			
		||||
	// Retrieve the mining dataset
 | 
			
		||||
	dataset, size := ethash.dataset(block.NumberU64()), datasetSize(block.NumberU64())
 | 
			
		||||
 | 
			
		||||
	// Start generating random nonces until we abort or find a good one
 | 
			
		||||
	var (
 | 
			
		||||
		hash     = block.HashNoNonce().Bytes()
 | 
			
		||||
		diff     = block.Difficulty()
 | 
			
		||||
		target   = new(big.Int).Div(maxUint256, diff)
 | 
			
		||||
		dataset  = ethash.dataset(block.NumberU64())
 | 
			
		||||
		rand     = rand.New(rand.NewSource(time.Now().UnixNano()))
 | 
			
		||||
		nonce    = uint64(rand.Int63())
 | 
			
		||||
		attempts int64
 | 
			
		||||
 | 
			
		||||
		rand  = rand.New(rand.NewSource(time.Now().UnixNano()))
 | 
			
		||||
		nonce = uint64(rand.Int63())
 | 
			
		||||
	)
 | 
			
		||||
	// Start generating random nonces until we abort or find a good one
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-stop:
 | 
			
		||||
@@ -511,7 +505,7 @@ func (ethash *Ethash) Search(block Block, stop <-chan struct{}) (uint64, []byte)
 | 
			
		||||
				attempts = 0
 | 
			
		||||
			}
 | 
			
		||||
			// Compute the PoW value of this nonce
 | 
			
		||||
			digest, result := hashimotoFull(size, dataset, hash, nonce)
 | 
			
		||||
			digest, result := hashimotoFull(dataset, hash, nonce)
 | 
			
		||||
			if new(big.Int).SetBytes(result).Cmp(target) <= 0 {
 | 
			
		||||
				return nonce, digest
 | 
			
		||||
			}
 | 
			
		||||
@@ -532,7 +526,7 @@ func (ethash *Ethash) dataset(block uint64) []uint32 {
 | 
			
		||||
	current, future := ethash.datasets[epoch], (*dataset)(nil)
 | 
			
		||||
	if current == nil {
 | 
			
		||||
		// No in-memory dataset, evict the oldest if the dataset limit was reached
 | 
			
		||||
		for len(ethash.datasets) >= ethash.dagsinmem {
 | 
			
		||||
		for len(ethash.datasets) > 0 && len(ethash.datasets) >= ethash.dagsinmem {
 | 
			
		||||
			var evict *dataset
 | 
			
		||||
			for _, dataset := range ethash.datasets {
 | 
			
		||||
				if evict == nil || evict.used.After(dataset.used) {
 | 
			
		||||
 
 | 
			
		||||
@@ -349,12 +349,12 @@ func hashimotoLight(size uint64, cache []uint32, hash []byte, nonce uint64) ([]b
 | 
			
		||||
// hashimotoFull aggregates data from the full dataset (using the full in-memory
 | 
			
		||||
// dataset) in order to produce our final value for a particular header hash and
 | 
			
		||||
// nonce.
 | 
			
		||||
func hashimotoFull(size uint64, dataset []uint32, hash []byte, nonce uint64) ([]byte, []byte) {
 | 
			
		||||
func hashimotoFull(dataset []uint32, hash []byte, nonce uint64) ([]byte, []byte) {
 | 
			
		||||
	lookup := func(index uint32) []uint32 {
 | 
			
		||||
		offset := index * hashWords
 | 
			
		||||
		return dataset[offset : offset+hashWords]
 | 
			
		||||
	}
 | 
			
		||||
	return hashimoto(hash, nonce, size, lookup)
 | 
			
		||||
	return hashimoto(hash, nonce, uint64(len(dataset))*4, lookup)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// datasetSizes is a lookup table for the ethash dataset size for the first 2048
 | 
			
		||||
 
 | 
			
		||||
@@ -660,7 +660,7 @@ func TestHashimoto(t *testing.T) {
 | 
			
		||||
	if !bytes.Equal(result, wantResult) {
 | 
			
		||||
		t.Errorf("light hashimoto result mismatch: have %x, want %x", result, wantResult)
 | 
			
		||||
	}
 | 
			
		||||
	digest, result = hashimotoFull(32*1024, dataset, hash, nonce)
 | 
			
		||||
	digest, result = hashimotoFull(dataset, hash, nonce)
 | 
			
		||||
	if !bytes.Equal(digest, wantDigest) {
 | 
			
		||||
		t.Errorf("full hashimoto digest mismatch: have %x, want %x", digest, wantDigest)
 | 
			
		||||
	}
 | 
			
		||||
@@ -713,6 +713,17 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) {
 | 
			
		||||
	pend.Wait()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTestMode(t *testing.T) {
 | 
			
		||||
	head := &types.Header{Difficulty: big.NewInt(100)}
 | 
			
		||||
	ethash := NewTestEthash()
 | 
			
		||||
	nonce, mix := ethash.Search(types.NewBlockWithHeader(head), nil)
 | 
			
		||||
	head.Nonce = types.EncodeNonce(nonce)
 | 
			
		||||
	copy(head.MixDigest[:], mix)
 | 
			
		||||
	if err := ethash.Verify(types.NewBlockWithHeader(head)); err != nil {
 | 
			
		||||
		t.Error("unexpected Verify error:", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Benchmarks the cache generation performance.
 | 
			
		||||
func BenchmarkCacheGeneration(b *testing.B) {
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
@@ -758,6 +769,6 @@ func BenchmarkHashimotoFullSmall(b *testing.B) {
 | 
			
		||||
 | 
			
		||||
	b.ResetTimer()
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		hashimotoFull(32*65536, dataset, hash, 0)
 | 
			
		||||
		hashimotoFull(dataset, hash, 0)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user