func CalcBlockTaxSubsidy(subsidyCache *SubsidyCache, keyheight int64, voters uint16,
	params *chaincfg.Params) int64 {
	if params.BlockTaxProportion == 0 {
		return 0
	}
	subsidy := subsidyCache.CalcBlockSubsidy(keyheight)
	proportionTax := int64(params.BlockTaxProportion)
	proportions := int64(params.TotalSubsidyProportions())
	subsidy *= proportionTax
	subsidy /= proportions
	keyheight = keyheight + 1
	if keyheight < params.StakeValidationHeight {
		voters = 5
	}
	if voters == 0 && keyheight >= params.StakeValidationHeight {
		return 0
	}
	potentialVoters := params.TicketsPerBlock
	adjusted := (int64(voters) * subsidy) / int64(potentialVoters)
	return adjusted
}
CalcBlockTaxSubsidy calculates the subsidy for the organization address in the
coinbase.

Safe for concurrent access.
package blockchain
import (
	"bytes"
	"fmt"
	"sync"
	"github.com/HcashOrg/hcashd/blockchain/stake"
	"github.com/HcashOrg/hcashd/chaincfg"
	"github.com/HcashOrg/hcashd/txscript"
	"github.com/HcashOrg/hcashd/wire"
	"github.com/HcashOrg/hcashutil"
)
const subsidyCacheInitWidth = 4
type SubsidyCache struct {
	subsidyCache     map[uint64]int64
	subsidyCacheLock sync.RWMutex
	params *chaincfg.Params
}
func NewSubsidyCache(keyHeight int64, params *chaincfg.Params) *SubsidyCache {
	scm := make(map[uint64]int64)
	sc := SubsidyCache{
		subsidyCache: scm,
		params:       params,
	}
	iteration := uint64(keyHeight / params.SubsidyReductionInterval)
	if iteration < subsidyCacheInitWidth {
		return &sc
	}
	for i := iteration - 4; i <= iteration; i++ {
		sc.CalcBlockSubsidy(int64(iteration) * params.SubsidyReductionInterval)
	}
	return &sc
}
func (s *SubsidyCache) CalcBlockSubsidy(keyheight int64) int64 {
	if keyheight == 0 {
		return s.params.BlockOneSubsidy()
	}
	iteration := uint64(keyheight / s.params.SubsidyReductionInterval)
	if iteration == 0 {
		return s.params.BaseSubsidy
	}
	s.subsidyCacheLock.RLock()
	cachedValue, existsInCache := s.subsidyCache[iteration]
	s.subsidyCacheLock.RUnlock()
	if existsInCache {
		return cachedValue
	}
	s.subsidyCacheLock.RLock()
	cachedValue, existsInCache = s.subsidyCache[iteration-1]
	s.subsidyCacheLock.RUnlock()
	if existsInCache {
		cachedValue *= s.params.MulSubsidy
		cachedValue /= s.params.DivSubsidy
		s.subsidyCacheLock.Lock()
		s.subsidyCache[iteration] = cachedValue
		s.subsidyCacheLock.Unlock()
		return cachedValue
	}
	subsidy := s.params.BaseSubsidy
	for i := uint64(0); i < iteration; i++ {
		subsidy *= s.params.MulSubsidy
		subsidy /= s.params.DivSubsidy
	}
	s.subsidyCacheLock.Lock()
	s.subsidyCache[iteration] = subsidy
	s.subsidyCacheLock.Unlock()
	return subsidy
}
func CalcBlockWorkSubsidy(subsidyCache *SubsidyCache,
	keyheight int64, voters uint16, params *chaincfg.Params) int64 {
	subsidy := subsidyCache.CalcBlockSubsidy(keyheight)
	proportionWork := int64(params.WorkRewardProportion)
	proportions := int64(params.TotalSubsidyProportions())
	subsidy *= proportionWork
	subsidy /= proportions
	keyheight = keyheight + 1
	if keyheight < params.StakeValidationHeight {
		return subsidy
	}
	if voters == 0 {
		return 0
	}
	potentialVoters := params.TicketsPerBlock
	actual := (int64(voters) * subsidy) / int64(potentialVoters)
	return actual
}
func CalcStakeVoteSubsidy(subsidyCache *SubsidyCache, height int64,
	params *chaincfg.Params) int64 {
	subsidy := subsidyCache.CalcBlockSubsidy(height)
	proportionStake := int64(params.StakeRewardProportion)
	proportions := int64(params.TotalSubsidyProportions())
	subsidy *= proportionStake
	subsidy /= (proportions * int64(params.TicketsPerBlock))
	return subsidy
}