func (b *BlockChain) FetchSubsidyCache() *SubsidyCache {
	return b.subsidyCache
}
FetchSubsidyCache returns the current subsidy cache from the blockchain.

This function is safe for concurrent access.
package blockchain
import (
	"container/list"
	"fmt"
	"math/big"
	"sort"
	"sync"
	"time"
	"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/txscript"
	"github.com/HcashOrg/hcashd/wire"
	"github.com/HcashOrg/hcashutil"
)
const (
	maxOrphanBlocks = 500
	minMemoryNodes = 2880
	minMemoryStakeNodes = 288
	mainchainBlockCacheSize = 12
	maxSearchDepth = 2880
)
type VoteVersionTuple struct {
	Version uint32
	Bits    uint16
}
type blockNode struct {
	parent *blockNode
	children []*blockNode
	hash chainhash.Hash
	height int64
	keyHeight int64
	totalFees int64
	workSum *big.Int
	inMainChain bool
	header wire.BlockHeader
	stakeDataLock  sync.Mutex
	stakeNode      *stake.Node
	newTickets     []chainhash.Hash
	stakeUndoData  stake.UndoTicketDataSlice
	ticketsSpent   []chainhash.Hash
	ticketsRevoked []chainhash.Hash
	votes []VoteVersionTuple
	isKeyBlock bool
}
func newBlockNode(block *hcashutil.Block, ticketsSpent []chainhash.Hash, ticketsRevoked []chainhash.Hash, votes []VoteVersionTuple) *blockNode {
	blockHeader := block.MsgBlock().Header
	blockHash := blockHeader.BlockHash()
	blockHashBigInt := HashToBig(&blockHash)
	workSum := big.NewInt(0)
	isKeyBlock := false
	totalFees := int64(0)
	if blockHashBigInt.Cmp(CompactToBig(blockHeader.Bits)) <= 0 {
		isKeyBlock = true
		workSum = CalcWork(blockHeader.Bits)
		isKeyBlock = true
	}
	for index, tx := range block.Transactions() {
		if index < 1 {
			continue
		}
		if isKeyBlock && index < 2 {
			continue
		}
		totalTxIn := int64(0)
		for _, txin := range tx.MsgTx().TxIn {
			totalTxIn += txin.ValueIn
		}
		totalTxOut := int64(0)
		for _, txout := range tx.MsgTx().TxOut {
			totalTxOut += txout.Value
		}
		totalFees += totalTxIn - totalTxOut
	}
	node := blockNode{
		hash:           blockHeader.BlockHash(),
		workSum:        workSum,
		height:         int64(blockHeader.Height),
		keyHeight:      int64(blockHeader.KeyHeight),
		isKeyBlock:     isKeyBlock,
		totalFees:      totalFees,
		header:         blockHeader,
		ticketsSpent:   ticketsSpent,
		ticketsRevoked: ticketsRevoked,
		votes:          votes,
	}
	return &node
}
type orphanBlock struct {
	block      *hcashutil.Block
	expiration time.Time
}
func removeChildNode(children []*blockNode, node *blockNode) []*blockNode {
	if node == nil {
		return children
	}
	for i := 0; i < len(children); i++ {
		if children[i].hash == node.hash {
			copy(children[i:], children[i+1:])
			children[len(children)-1] = nil
			return children[:len(children)-1]
		}
	}
	return children
}
type BestState struct {
	Hash         *chainhash.Hash  
	Height       int64            
	KeyHeight    int64            
	Bits         uint32           
	BlockSize    uint64           
	NumTxns      uint64           
	TotalTxns    uint64           
	MedianTime   time.Time        
	TotalSubsidy int64            
}
func newBestState(node *blockNode, blockSize, numTxns, totalTxns uint64, medianTime time.Time, totalSubsidy int64) *BestState {
	return &BestState{
		Hash:         &node.hash,
		Height:       node.height,
		KeyHeight:    node.keyHeight,
		Bits:         node.header.Bits,
		BlockSize:    blockSize,
		NumTxns:      numTxns,
		TotalTxns:    totalTxns,
		MedianTime:   medianTime,
		TotalSubsidy: totalSubsidy,
	}
}
type BlockChain struct {
	checkpointsByHeight map[int64]*chaincfg.Checkpoint
	db                  database.DB
	dbInfo              *databaseInfo
	chainParams         *chaincfg.Params
	timeSource          MedianTimeSource
	notifications       NotificationCallback
	sigCache            *txscript.SigCache
	indexManager        IndexManager
	subsidyCache *SubsidyCache
	chainLock sync.RWMutex
	noVerify      bool
	noCheckpoints bool
	bestNode *blockNode
	index    map[chainhash.Hash]*blockNode
	depNodes map[chainhash.Hash][]*blockNode
	orphanLock     sync.RWMutex
	orphans        map[chainhash.Hash]*orphanBlock
	prevOrphans    map[chainhash.Hash][]*orphanBlock
	oldestOrphan   *orphanBlock
	blockCacheLock sync.RWMutex
	blockCache     map[chainhash.Hash]*hcashutil.Block
	mainchainBlockCacheLock sync.RWMutex
	mainchainBlockCache     map[chainhash.Hash]*hcashutil.Block
	mainchainBlockCacheSize int
	nextCheckpoint  *chaincfg.Checkpoint
	checkpointBlock *hcashutil.Block
	stateLock     sync.RWMutex
	stateSnapshot *BestState
	deploymentCaches map[uint32][]thresholdStateCache
	pruner *chainPruner
	isVoterMajorityVersionCache   map[[stakeMajorityCacheKeySize]byte]bool
	isStakeMajorityVersionCache   map[[stakeMajorityCacheKeySize]byte]bool
	calcPriorStakeVersionCache    map[[chainhash.HashSize]byte]uint32
	calcVoterVersionIntervalCache map[[chainhash.HashSize]byte]uint32
	calcStakeVersionCache         map[[chainhash.HashSize]byte]uint32
}
const (
	stakeMajorityCacheKeySize = 4 + chainhash.HashSize
)
type StakeVersions struct {
	Hash         chainhash.Hash
	Height       int64
	BlockVersion int32
	StakeVersion uint32
	Votes        []VoteVersionTuple
}
func (b *BlockChain) GetBlockKeyHeight(height int64) (int64, error) {
	keyHeight, err := b.KeyHeightByHeight(height, nil)
	if err != nil {
		return -1, err
	}
	return keyHeight, nil
}
func (b *BlockChain) GetStakeVersions(hash *chainhash.Hash, count int32) ([]StakeVersions, error) {
	exists, err := b.HaveBlock(hash)
	if err != nil {
		return nil, err
	}
	if !exists {
		return nil, fmt.Errorf("hash '%s' not found on chain", hash.String())
	}
	if count == 0 {
		return nil, nil
	}
	if count < 0 {
		return nil, fmt.Errorf("count must not be less than zero - "+
			"got %d", count)
	}
	b.chainLock.Lock()
	defer b.chainLock.Unlock()
	if count > int32(b.bestNode.height) {
		count = int32(b.bestNode.height)
	}
	startNode, err := b.findNode(hash, 0)
	if err != nil {
		return nil, err
	}
	result := make([]StakeVersions, 0, count)
	prevNode := startNode
	for i := int32(0); prevNode != nil && i < count; i++ {
		sv := StakeVersions{
			Hash:         prevNode.hash,
			Height:       prevNode.height,
			BlockVersion: prevNode.header.Version,
			StakeVersion: prevNode.header.StakeVersion,
			Votes:        prevNode.votes,
		}
		result = append(result, sv)
		prevNode, err = b.getPrevNodeFromNode(prevNode)
		if err != nil {
			return nil, err
		}
	}
	return result, nil
}
type VoteInfo struct {
	Agendas      []chaincfg.ConsensusDeployment
	AgendaStatus []ThresholdStateTuple
}
func (b *BlockChain) GetVoteInfo(hash *chainhash.Hash, version uint32) (*VoteInfo, error) {
	deployments, ok := b.chainParams.Deployments[version]
	if !ok {
		return nil, VoteVersionError(version)
	}
	if !ok {
		return nil, HashError(hash.String())
	}
	vi := VoteInfo{
		Agendas: make([]chaincfg.ConsensusDeployment,
			0, len(deployments)),
		AgendaStatus: make([]ThresholdStateTuple, 0, len(deployments)),
	}
	for _, deployment := range deployments {
		vi.Agendas = append(vi.Agendas, deployment)
		status, err := b.ThresholdState(hash, version, deployment.Vote.Id)
		if err != nil {
			return nil, err
		}
		vi.AgendaStatus = append(vi.AgendaStatus, status)
	}
	return &vi, nil
}
func (b *BlockChain) DisableVerify(disable bool) {
	b.chainLock.Lock()
	b.noVerify = disable
	b.chainLock.Unlock()
}
func (b *BlockChain) TotalSubsidy() int64 {
	b.chainLock.RLock()
	ts := b.BestSnapshot().TotalSubsidy
	b.chainLock.RUnlock()
	return ts
}