func (b *BlockChain) IsCheckpointCandidate(block *cashutil.Block) (bool, error) {
	b.chainLock.RLock()
	defer b.chainLock.RUnlock()
	node := b.index.LookupNode(block.Hash())
	if node == nil || !b.bestChain.Contains(node) {
		return false, nil
	}
	if node.height != block.Height() {
		return false, fmt.Errorf("passed block height of %d does not "+
			"match the main chain height of %d", block.Height(),
			node.height)
	}
	mainChainHeight := b.bestChain.Tip().height
	if node.height > (mainChainHeight - CheckpointConfirmations) {
		return false, nil
	}
	nextNode := b.bestChain.Next(node)
	if nextNode == nil {
		return false, nil
	}
	if node.parent == nil {
		return false, nil
	}
	prevTime := time.Unix(node.parent.timestamp, 0)
	curTime := block.MsgBlock().Header.Timestamp
	nextTime := time.Unix(nextNode.timestamp, 0)
	if prevTime.After(curTime) || nextTime.Before(curTime) {
		return false, nil
	}
	for _, tx := range block.Transactions() {
		if isNonstandardTransaction(tx) {
			return false, nil
		}
	}
	return true, nil
}
IsCheckpointCandidate returns whether or not the passed block is a good
checkpoint candidate.

The factors used to determine a good checkpoint are:
- The block must be in the main chain
- The block must be at least 'CheckpointConfirmations' blocks prior to the
current end of the main chain
- The timestamps for the blocks before and after the checkpoint must have
timestamps which are also before and after the checkpoint, respectively
(due to the median time allowance this is not always the case)
- The block must not contain any strange transaction such as those with
nonstandard scripts

The intent is that candidates are reviewed by a developer to make the final
decision and then manually added to the list of checkpoints for a network.

This function is safe for concurrent access.
package blockchain
import (
	"fmt"
	"time"
	"github.com/bcext/cashutil"
	"github.com/bcext/gcash/chaincfg"
	"github.com/bcext/gcash/chaincfg/chainhash"
	"github.com/bcext/gcash/txscript"
)
const CheckpointConfirmations = 2016
func newHashFromStr(hexStr string) *chainhash.Hash {
	hash, _ := chainhash.NewHashFromStr(hexStr)
	return hash
}
func (b *BlockChain) Checkpoints() []chaincfg.Checkpoint {
	return b.checkpoints
}
func (b *BlockChain) HasCheckpoints() bool {
	return len(b.checkpoints) > 0
}
func (b *BlockChain) LatestCheckpoint() *chaincfg.Checkpoint {
	if !b.HasCheckpoints() {
		return nil
	}
	return &b.checkpoints[len(b.checkpoints)-1]
}
func (b *BlockChain) verifyCheckpoint(height int32, hash *chainhash.Hash) bool {
	if !b.HasCheckpoints() {
		return true
	}
	checkpoint, exists := b.checkpointsByHeight[height]
	if !exists {
		return true
	}
	if !checkpoint.Hash.IsEqual(hash) {
		return false
	}
	log.Infof("Verified checkpoint at height %d/block %s", checkpoint.Height,
		checkpoint.Hash)
	return true
}
func (b *BlockChain) findPreviousCheckpoint() (*blockNode, error) {
	if !b.HasCheckpoints() {
		return nil, nil
	}
	checkpoints := b.checkpoints
	numCheckpoints := len(checkpoints)
	if b.checkpointNode == nil && b.nextCheckpoint == nil {
		for i := numCheckpoints - 1; i >= 0; i-- {
			node := b.index.LookupNode(checkpoints[i].Hash)
			if node == nil || !b.bestChain.Contains(node) {
				continue
			}
			b.checkpointNode = node
			if i < numCheckpoints-1 {
				b.nextCheckpoint = &checkpoints[i+1]
			}
			return b.checkpointNode, nil
		}
		b.nextCheckpoint = &checkpoints[0]
		return nil, nil
	}
	if b.nextCheckpoint == nil {
		return b.checkpointNode, nil
	}
	if b.bestChain.Tip().height < b.nextCheckpoint.Height {
		return b.checkpointNode, nil
	}
	checkpointNode := b.index.LookupNode(b.nextCheckpoint.Hash)
	if checkpointNode == nil {
		return nil, AssertError(fmt.Sprintf("findPreviousCheckpoint "+
			"failed lookup of known good block node %s",
			b.nextCheckpoint.Hash))
	}
	b.checkpointNode = checkpointNode
	checkpointIndex := -1
	for i := numCheckpoints - 1; i >= 0; i-- {
		if checkpoints[i].Hash.IsEqual(b.nextCheckpoint.Hash) {
			checkpointIndex = i
			break
		}
	}
	b.nextCheckpoint = nil
	if checkpointIndex != -1 && checkpointIndex < numCheckpoints-1 {
		b.nextCheckpoint = &checkpoints[checkpointIndex+1]
	}
	return b.checkpointNode, nil
}
func isNonstandardTransaction(tx *cashutil.Tx) bool {
	for _, txOut := range tx.MsgTx().TxOut {
		scriptClass := txscript.GetScriptClass(txOut.PkScript)
		if scriptClass == txscript.NonStandardTy {
			return true
		}
	}
	return false
}