cpuminer: Fix off-by-one issues in nonce handling.

During 32-bit nonce iteration, if a block solution wasn't found, the
iterator variable would overflow back to 0, creating an infinite loop,
thus continuing the puzzle search without ever updating the extra
nonce field.  This bug has never been triggered in practice because
the code in question has only ever been used with difficulties where
a solution exists within the regular nonce space.

The extra nonce iteration logic itself was also imperfect in that it
wouldn't test a value of exactly 2^64 - 1.

The behavior we actually want is to loop through the entire unsigned
integer space for both the regular and extra nonces, and for this
process to continue forever until a solution is found.  Note that
periodic updates to the block header timestamp during iteration ensure
that unique hashes are generated for subsequent generations of the
same nonce values.
This commit is contained in:
Aaron Campbell 2019-08-25 07:15:03 -04:00 committed by Dave Collins
parent cb79063ef8
commit adff6a0bac

View File

@ -250,8 +250,10 @@ func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, ticker *time.Ticker, quit
// Note that the entire extra nonce range is iterated and the offset is
// added relying on the fact that overflow will wrap around 0 as
// provided by the Go spec.
for extraNonce := uint64(0); extraNonce < maxExtraNonce; extraNonce++ {
// provided by the Go spec. Furthermore, the break condition has been
// intentionally omitted such that the loop will continue forever until
// a solution is found.
for extraNonce := uint64(0); ; extraNonce++ {
// Update the extra nonce in the block template header with the
// new value.
littleEndian.PutUint64(header.ExtraData[:], extraNonce+enOffset)
@ -259,7 +261,15 @@ func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, ticker *time.Ticker, quit
// Search through the entire nonce range for a solution while
// periodically checking for early quit and stale block
// conditions along with updates to the speed monitor.
for i := uint32(0); i <= maxNonce; i++ {
//
// This loop differs from the outer one in that it does not run
// forever, thus allowing the extraNonce field to be updated
// between each successive iteration of the regular nonce
// space. Note that this is achieved by placing the break
// condition at the end of the code block, as this prevents the
// infinite loop that would otherwise occur if we let the for
// statement overflow the nonce value back to 0.
for nonce := uint32(0); ; nonce++ {
select {
case <-quit:
return false
@ -294,7 +304,7 @@ func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, ticker *time.Ticker, quit
}
// Update the nonce and hash the block header.
header.Nonce = i
header.Nonce = nonce
hash := header.BlockHash()
hashesCompleted++
@ -307,10 +317,12 @@ func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, ticker *time.Ticker, quit
}
return true
}
if nonce == maxNonce {
break
}
}
}
return false
}
// generateBlocks is a worker that is controlled by the miningWorkerController.