// limitNumOrphans limits the number of orphan transactions by evicting a random // orphan if adding a new one would cause it to overflow the max allowed. // // This function MUST be called with the mempool lock held (for writes). func (mp *txMemPool) limitNumOrphans() error { if len(mp.orphans)+1 > mp.cfg.MaxOrphanTxs && mp.cfg.MaxOrphanTxs > 0 { // Generate a cryptographically random hash. randHashBytes := make([]byte, wire.HashSize) _, err := rand.Read(randHashBytes) if err != nil { return err } randHashNum := new(big.Int).SetBytes(randHashBytes) // Try to find the first entry that is greater than the random // hash. Use the first entry (which is already pseudorandom due // to Go's range statement over maps) as a fallback if none of // the hashes in the orphan pool are larger than the random // hash. var foundHash *wire.ShaHash for txHash := range mp.orphans { if foundHash == nil { foundHash = &txHash } txHashNum := blockchain.ShaHashToBig(&txHash) if txHashNum.Cmp(randHashNum) > 0 { foundHash = &txHash break } } mp.removeOrphan(foundHash) } return nil }
/* checkProofOfWork verifies the header hashes into something lower than specified by the 4-byte bits field. */ func checkProofOfWork(header wire.BlockHeader, p *chaincfg.Params) bool { target := blockchain.CompactToBig(header.Bits) // The target must more than 0. Why can you even encode negative... if target.Sign() <= 0 { log.Printf("block target %064x is neagtive(??)\n", target.Bytes()) return false } // The target must be less than the maximum allowed (difficulty 1) if target.Cmp(p.PowLimit) > 0 { log.Printf("block target %064x is "+ "higher than max of %064x", target, p.PowLimit.Bytes()) return false } // The header hash must be less than the claimed target in the header. blockHash := header.BlockSha() hashNum := blockchain.ShaHashToBig(&blockHash) if hashNum.Cmp(target) > 0 { log.Printf("block hash %064x is higher than "+ "required target of %064x", hashNum, target) return false } return true }
// solveBlock attempts to find some combination of a nonce, extra nonce, and // current timestamp which makes the passed block hash to a value less than the // target difficulty. The timestamp is updated periodically and the passed // block is modified with all tweaks during this process. This means that // when the function returns true, the block is ready for submission. // // This function will return early with false when conditions that trigger a // stale block such as a new block showing up or periodically when there are // new transactions and enough time has elapsed without finding a solution. func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32, ticker *time.Ticker, quit chan struct{}) bool { // Choose a random extra nonce offset for this block template and // worker. enOffset, err := wire.RandomUint64() if err != nil { minrLog.Errorf("Unexpected error while generating random "+ "extra nonce offset: %v", err) enOffset = 0 } // Create a couple of convenience variables. header := &msgBlock.Header targetDifficulty := blockchain.CompactToBig(header.Bits) // Initial state. lastGenerated := time.Now() lastTxUpdate := m.txSource.LastUpdated() hashesCompleted := uint64(0) // 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++ { // Update the extra nonce in the block template with the // new value by regenerating the coinbase script and // setting the merkle root to the new value. The UpdateExtraNonce(msgBlock, blockHeight, extraNonce+enOffset) // 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++ { select { case <-quit: return false case <-ticker.C: m.updateHashes <- hashesCompleted hashesCompleted = 0 // The current block is stale if the best block // has changed. bestHash, _ := m.server.blockManager.chainState.Best() if !header.PrevBlock.IsEqual(bestHash) { return false } // The current block is stale if the memory pool // has been updated since the block template was // generated and it has been at least one // minute. if lastTxUpdate != m.txSource.LastUpdated() && time.Now().After(lastGenerated.Add(time.Minute)) { return false } UpdateBlockTime(msgBlock, m.server.blockManager) default: // Non-blocking select to fall through } // Update the nonce and hash the block header. Each // hash is actually a double sha256 (two hashes), so // increment the number of hashes completed for each // attempt accordingly. header.Nonce = i hash := header.BlockSha() hashesCompleted += 2 // The block is solved when the new block hash is less // than the target difficulty. Yay! if blockchain.ShaHashToBig(&hash).Cmp(targetDifficulty) <= 0 { m.updateHashes <- hashesCompleted return true } } } return false }