func (b *blockManager) current() bool {
	if !b.chain.IsCurrent() {
		return false
	}
	if b.syncPeer == nil {
		return true
	}
	best := b.chain.BestSnapshot()
	realKeyHeight := best.KeyHeight
	if blockchain.HashToBig(best.Hash).Cmp(blockchain.CompactToBig(best.Bits)) <= 0{
		realKeyHeight++
	}
	if realKeyHeight < b.syncPeer.LastKeyBlock() {
		return false
	}
	if realKeyHeight == b.syncPeer.LastKeyBlock() && best.Height < b.syncPeer.LastBlock() {
		return false
	}
	return true
}
current returns true if we believe we are synced with our peers, false if we
still have blocks to check
package main
import (
	"container/list"
	"encoding/binary"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"sync"
	"sync/atomic"
	"time"
	"github.com/HcashOrg/hcashd/blockchain"
	"github.com/HcashOrg/hcashd/blockchain/stake"
	"github.com/HcashOrg/hcashd/chaincfg"
	"github.com/HcashOrg/hcashd/chaincfg/chainhash"
	"github.com/HcashOrg/hcashd/database"
	"github.com/HcashOrg/hcashd/mempool"
	"github.com/HcashOrg/hcashd/wire"
	"github.com/HcashOrg/hcashutil"
)
var BlockManager *blockManager
func SetBlockManager(bm *blockManager){
	BlockManager = bm
}
func getBlockManager() *blockManager{
	return BlockManager
}
const (
	minInFlightBlocks = 10
	blockDbNamePrefix = "blocks"
	maxResendLimit = 3
	maxRejectedTxns = 1000
	maxRequestedBlocks = wire.MaxInvPerMsg
	maxRequestedTxns = wire.MaxInvPerMsg
	maxLotteryDataBlockDelta = 288
)
var zeroHash chainhash.Hash
type newPeerMsg struct {
	peer *serverPeer
}
type blockMsg struct {
	block *hcashutil.Block
	peer  *serverPeer
}
type invMsg struct {
	inv  *wire.MsgInv
	peer *serverPeer
}
type headersMsg struct {
	headers *wire.MsgHeaders
	peer    *serverPeer
}
type donePeerMsg struct {
	peer *serverPeer
}
type txMsg struct {
	tx   *hcashutil.Tx
	peer *serverPeer
}
type getSyncPeerMsg struct {
	reply chan *serverPeer
}
type requestFromPeerMsg struct {
	peer   *serverPeer
	blocks []*chainhash.Hash
	txs    []*chainhash.Hash
	reply  chan requestFromPeerResponse
}
type requestFromPeerResponse struct {
	err error
}
type calcNextReqDifficultyResponse struct {
	difficulty uint32
	err        error
}
type calcNextReqDifficultyMsg struct {
	timestamp time.Time
	reply     chan calcNextReqDifficultyResponse
}
type calcNextReqDiffNodeMsg struct {
	hash      *chainhash.Hash
	timestamp time.Time
	reply     chan calcNextReqDifficultyResponse
}
type calcNextReqStakeDifficultyResponse struct {
	stakeDifficulty int64
	err             error
}
type calcNextReqStakeDifficultyMsg struct {
	reply chan calcNextReqStakeDifficultyResponse
}
type getGenerationResponse struct {
	hashes []chainhash.Hash
	err    error
}
type getKeyGenerationResponse struct {
	hashes []chainhash.Hash
	err    error
}
type getMatchedDescendantsResponse struct {
	hashes []chainhash.Hash
	err    error
}
type getDescendantsResponse struct {
	hashes []chainhash.Hash
	err    error
}
type getGenerationMsg struct {
	hash  chainhash.Hash
	reply chan getGenerationResponse
}
type getKeyGenerationMsg struct {
	hash  chainhash.Hash
	reply chan getKeyGenerationResponse
}
type getMatchedDescendantsMsg struct {
	hash  chainhash.Hash
	voteResult uint16
	reply chan getMatchedDescendantsResponse
}
type getDescendantsMsg struct {
	hash  chainhash.Hash
	reply chan getDescendantsResponse
}
type forceReorganizationResponse struct {
	err error
}
type forceReorganizationMsg struct {
	formerBest chainhash.Hash
	newBest    chainhash.Hash
	reply      chan forceReorganizationResponse
}
type getTopBlockResponse struct {
	block *hcashutil.Block
	err   error
}
type getTopBlockMsg struct {
	reply chan getTopBlockResponse
}
type processBlockResponse struct {
	onMainChain bool
	isOrphan    bool
	err         error
}
type processBlockMsg struct {
	block *hcashutil.Block
	flags blockchain.BehaviorFlags
	reply chan processBlockResponse
}
type processTransactionResponse struct {
	acceptedTxs []*hcashutil.Tx
	err         error
}
type processTransactionMsg struct {
	tx            *hcashutil.Tx
	allowOrphans  bool
	rateLimit     bool
	allowHighFees bool
	reply         chan processTransactionResponse
}
type isCurrentMsg struct {
	reply chan bool
}
type pauseMsg struct {
	unpause <-chan struct{}
}
type getCurrentTemplateMsg struct {
	reply chan getCurrentTemplateResponse
}
type getCurrentTemplateResponse struct {
	Template *BlockTemplate
}
type setCurrentTemplateMsg struct {
	Template *BlockTemplate
	reply    chan setCurrentTemplateResponse
}
type setCurrentTemplateResponse struct {
}
type getParentTemplateMsg struct {
	reply chan getParentTemplateResponse
}
type getParentTemplateResponse struct {
	Template *BlockTemplate
}
type setParentTemplateMsg struct {
	Template *BlockTemplate
	reply    chan setParentTemplateResponse
}
type setParentTemplateResponse struct {
}
type headerNode struct {
	height int64
	hash   *chainhash.Hash
	prevKeyHash *chainhash.Hash
}
type chainState struct {
	sync.Mutex
	newestHash          *chainhash.Hash
	newestHeight        int64
	newestKeyHeight     int64
	newestBits          uint32
	nextFinalState      [6]byte
	nextPoolSize        uint32
	nextStakeDifficulty int64
	winningTickets      []chainhash.Hash
	missedTickets       []chainhash.Hash
	curPrevHash         chainhash.Hash
	curPrevKeyHash      chainhash.Hash
	pastMedianTime      time.Time
	stakeVersion        uint32
}
func (c *chainState) Best() (*chainhash.Hash, int64, int64) {
	c.Lock()
	defer c.Unlock()
	return c.newestHash, c.newestHeight, c.newestKeyHeight
}
func (c *chainState) NextFinalState() [6]byte {
	c.Lock()
	defer c.Unlock()
	return c.nextFinalState
}
func (c *chainState) NextPoolSize() uint32 {
	c.Lock()
	defer c.Unlock()
	return c.nextPoolSize
}
func (c *chainState) NextWinners() []chainhash.Hash {
	c.Lock()
	defer c.Unlock()
	return c.winningTickets
}
func (c *chainState) CurrentlyMissed() []chainhash.Hash {
	c.Lock()
	defer c.Unlock()
	return c.missedTickets
}
func (c *chainState) GetTopPrevHash() chainhash.Hash {
	c.Lock()
	defer c.Unlock()
	return c.curPrevHash
}
type blockManager struct {
	server              *server
	started             int32
	shutdown            int32
	chain               *blockchain.BlockChain
	rejectedTxns        map[chainhash.Hash]struct{}
	requestedTxns       map[chainhash.Hash]struct{}
	requestedEverTxns   map[chainhash.Hash]uint8
	requestedBlocks     map[chainhash.Hash]struct{}
	requestedEverBlocks map[chainhash.Hash]uint8
	progressLogger      *blockProgressLogger
	syncPeer            *serverPeer
	msgChan             chan interface{}
	chainState          chainState
	wg                  sync.WaitGroup
	quit                chan struct{}
	headersFirstMode bool
	headerList       *list.List
	startHeader      *list.Element
	nextCheckpoint   *chaincfg.Checkpoint
	lotteryDataBroadcast      map[chainhash.Hash]struct{}
	lotteryDataBroadcastMutex sync.Mutex
	cachedCurrentTemplate *BlockTemplate
	cachedParentTemplate  *BlockTemplate
	AggressiveMining      bool
}
func (b *blockManager) resetHeaderState(newestHash *chainhash.Hash, newestHeight int64) {
	b.headersFirstMode = false
	b.headerList.Init()
	b.startHeader = nil
	if b.nextCheckpoint != nil {
		node := headerNode{height: newestHeight, hash: newestHash}
		b.headerList.PushBack(&node)
	}
}
func (b *blockManager) updateChainState(newestHash *chainhash.Hash,
	newestHeight int64, newestKeyHeight int64, newestBits uint32, finalState [6]byte, poolSize uint32,
	nextStakeDiff int64, winningTickets []chainhash.Hash,
	missedTickets []chainhash.Hash, curPrevHash chainhash.Hash, curPrevKeyHash chainhash.Hash) {
	b.chainState.Lock()
	defer b.chainState.Unlock()
	b.chainState.newestHash = newestHash
	b.chainState.newestHeight = newestHeight
	b.chainState.newestKeyHeight = newestKeyHeight
	b.chainState.newestBits = newestBits
	b.chainState.pastMedianTime = b.chain.BestSnapshot().MedianTime
	b.chainState.nextFinalState = finalState
	b.chainState.nextPoolSize = poolSize
	b.chainState.nextStakeDifficulty = nextStakeDiff
	b.chainState.winningTickets = winningTickets
	b.chainState.missedTickets = missedTickets
	b.chainState.curPrevHash = curPrevHash
	b.chainState.curPrevKeyHash = curPrevKeyHash
}
func (b *blockManager) findNextHeaderCheckpoint(height int64) *chaincfg.Checkpoint {
	if cfg.DisableCheckpoints {
		return nil
	}
	checkpoints := b.server.chainParams.Checkpoints
	if len(checkpoints) == 0 {
		return nil
	}
	finalCheckpoint := &checkpoints[len(checkpoints)-1]
	if height >= finalCheckpoint.Height {
		return nil
	}
	nextCheckpoint := finalCheckpoint
	for i := len(checkpoints) - 2; i >= 0; i-- {
		if height >= checkpoints[i].Height {
			break
		}
		nextCheckpoint = &checkpoints[i]
	}
	return nextCheckpoint
}
func (b *blockManager) startSync(peers *list.List) {
	if b.syncPeer != nil {
		return
	}
	best := b.chain.BestSnapshot()
	var bestPeer *serverPeer
	var enext *list.Element
	for e := peers.Front(); e != nil; e = enext {
		enext = e.Next()
		sp := e.Value.(*serverPeer)
		realKeyHeight := best.KeyHeight
		if blockchain.HashToBig(best.Hash).Cmp(blockchain.CompactToBig(best.Bits)) <= 0 {
			realKeyHeight++
		}
		if sp.LastKeyBlock() < realKeyHeight || (sp.LastKeyBlock() == realKeyHeight && sp.LastBlock() < best.Height) {
			peers.Remove(e)
			continue
		}
		bestPeer = sp
	}
	if bestPeer != nil {
		b.requestedBlocks = make(map[chainhash.Hash]struct{})
		locator, err := b.chain.LatestBlockLocator()
		if err != nil {
			bmgrLog.Errorf("Failed to get block locator for the "+
				"latest block: %v", err)
			return
		}
		bmgrLog.Infof("Syncing to block height %d and block keyheight %d from peer %v",
			bestPeer.LastBlock(), bestPeer.LastKeyBlock(), bestPeer.Addr())
		if b.nextCheckpoint != nil &&
			best.Height < b.nextCheckpoint.Height &&
			!cfg.DisableCheckpoints {
			err := bestPeer.PushGetHeadersMsg(locator, b.nextCheckpoint.Hash)
			if err != nil {
				bmgrLog.Errorf("Failed to push getheadermsg for the "+
					"latest blocks: %v", err)
				return
			}
			b.headersFirstMode = true
			bmgrLog.Infof("Downloading headers for blocks %d to "+
				"%d from peer %s", best.Height+1,
				b.nextCheckpoint.Height, bestPeer.Addr())
		} else {
			err := bestPeer.PushGetBlocksMsg(locator, &zeroHash)
			if err != nil {
				bmgrLog.Errorf("Failed to push getblocksmsg for the "+
					"latest blocks: %v", err)
				return
			}
		}
		b.syncPeer = bestPeer
	} else {
		bmgrLog.Warnf("No sync peer candidates available")
	}
}
func (b *blockManager) isSyncCandidate(sp *serverPeer) bool {
	return sp.Services()&wire.SFNodeNetwork == wire.SFNodeNetwork
}
func (b *blockManager) syncMiningStateAfterSync(sp *serverPeer) {
	go func() {
		for {
			time.Sleep(3 * time.Second)
			if !sp.Connected() {
				return
			}
			if b.IsCurrent() {
				msg := wire.NewMsgGetMiningState()
				sp.QueueMessage(msg, nil)
				return
			}
		}
	}()
}
func (b *blockManager) handleNewPeerMsg(peers *list.List, sp *serverPeer) {
	if atomic.LoadInt32(&b.shutdown) != 0 {
		return
	}
	bmgrLog.Infof("New valid peer %s (%s)", sp, sp.UserAgent())
	if !b.isSyncCandidate(sp) {
		return
	}
	peers.PushBack(sp)
	b.startSync(peers)
	if !cfg.NoMiningStateSync {
		b.syncMiningStateAfterSync(sp)
	}
}
func (b *blockManager) handleDonePeerMsg(peers *list.List, sp *serverPeer) {
	for e := peers.Front(); e != nil; e = e.Next() {
		if e.Value == sp {
			peers.Remove(e)
			break
		}
	}
	bmgrLog.Infof("Lost peer %s", sp)
	for k := range sp.requestedTxns {
		delete(b.requestedTxns, k)
	}
	for k := range sp.requestedBlocks {
		delete(b.requestedBlocks, k)
	}
	if b.syncPeer != nil && b.syncPeer == sp {
		b.syncPeer = nil
		if b.headersFirstMode {
			best := b.chain.BestSnapshot()
			b.resetHeaderState(best.Hash, best.Height)
		}
		b.startSync(peers)
	}
}
func (b *blockManager) handleTxMsg(tmsg *txMsg) {
	txHash := tmsg.tx.Hash()
	if _, exists := b.rejectedTxns[*txHash]; exists {
		bmgrLog.Debugf("Ignoring unsolicited previously rejected "+
			"transaction %v from %s", txHash, tmsg.peer)
		return
	}
	allowOrphans := cfg.MaxOrphanTxs > 0
	acceptedTxs, err := b.server.txMemPool.ProcessTransaction(b.chain, tmsg.tx,
		allowOrphans, true, true)
	delete(tmsg.peer.requestedTxns, *txHash)
	delete(b.requestedTxns, *txHash)
	if err != nil {
		b.rejectedTxns[*txHash] = struct{}{}
		b.limitMap(b.rejectedTxns, maxRejectedTxns)
		if _, ok := err.(mempool.RuleError); ok {
			bmgrLog.Debugf("Rejected transaction %v from %s: %v",
				txHash, tmsg.peer, err)
		} else {
			bmgrLog.Errorf("Failed to process transaction %v: %v",
				txHash, err)
		}
		code, reason := mempool.ErrToRejectErr(err)
		tmsg.peer.PushRejectMsg(wire.CmdTx, code, reason, txHash,
			false)
		return
	}
	b.server.AnnounceNewTransactions(acceptedTxs)
}