func (v *Validator) checkHeader(params ...interface{}) error {
	block := AssertBlock(params[0])
	powLimit := AssertBigInt(params[1])
	timeSource := AssertMedianTimeSource(params[2])
	header := block.Header
	headerSize := block.Header.GetHeaderSize()
	if headerSize > int(types.MaxBlockHeaderSize) {
		return errors.New("[checkHeader] checkHeader header is too big")
	}
	if err := header.GetAuxPow().SideAuxPowCheck(header.Hash()); err != nil {
		return errors.New("[powCheckHeader] block check side AuxPow is failed," + err.Error())
	}
	if err := v.checkProofOfWork(header, powLimit); err != nil {
		return errors.New("[powCheckHeader] block check proof is failed," + err.Error())
	}
	tempTime := time.Unix(int64(header.GetTimeStamp()), 0)
	if !tempTime.Equal(time.Unix(tempTime.Unix(), 0)) {
		return errors.New("[powCheckHeader] block timestamp of has a higher precision than one second")
	}
	maxTimestamp := timeSource.AdjustedTime().Add(time.Second * MaxTimeOffsetSeconds)
	if tempTime.After(maxTimestamp) {
		return errors.New("[powCheckHeader] block timestamp of is too far in the future")
	}
	return nil
}
block *Block, powLimit *big.Int, timeSource MedianTimeSource
package blockchain
import (
	"errors"
	"math"
	"math/big"
	"time"
	"github.com/elastos/Elastos.ELA.SideChain/interfaces"
	"github.com/elastos/Elastos.ELA.SideChain/spv"
	"github.com/elastos/Elastos.ELA.SideChain/types"
	"github.com/elastos/Elastos.ELA/common"
	"github.com/elastos/Elastos.ELA/crypto"
)
const (
	MaxTimeOffsetSeconds = 2 * 60 * 60
)
type BlockValidateAction struct {
	Name    ValidateFuncName
	Handler func(params ...interface{}) error
}
type Validator struct {
	chain                 *BlockChain
	spvService            *spv.Service
	checkSanityFunctions  []*BlockValidateAction
	checkContextFunctions []*BlockValidateAction
}
func NewValidator(chain *BlockChain, spv *spv.Service) *Validator {
	v := &Validator{
		chain:      chain,
		spvService: spv,
	}
	v.RegisterFunc(ValidateFuncNames.CheckHeader, v.checkHeader)
	v.RegisterFunc(ValidateFuncNames.CheckTransactionsCount, v.checkTransactionsCount)
	v.RegisterFunc(ValidateFuncNames.CheckBlockSize, v.checkBlockSize)
	v.RegisterFunc(ValidateFuncNames.CheckCoinBaseTransaction, v.checkCoinBaseTransaction)
	v.RegisterFunc(ValidateFuncNames.CheckTransactionsMerkle, v.checkTransactionsMerkle)
	v.RegisterContextFunc(ValidateFuncNames.CheckHeader, v.checkHeaderContext)
	return v
}
func (v *Validator) RegisterFunc(name ValidateFuncName, function func(params ...interface{}) error) {
	for _, action := range v.checkSanityFunctions {
		if action.Name == name {
			action.Handler = function
			return
		}
	}
	v.checkSanityFunctions = append(v.checkSanityFunctions, &BlockValidateAction{Name: name, Handler: function})
}
func (v *Validator) RegisterContextFunc(name ValidateFuncName, function func(params ...interface{}) error) {
	for _, action := range v.checkContextFunctions {
		if action.Name == name {
			action.Handler = function
			return
		}
	}
	v.checkContextFunctions = append(v.checkContextFunctions, &BlockValidateAction{Name: name, Handler: function})
}
func (v *Validator) CheckBlockSanity(block *types.Block, powLimit *big.Int, timeSource MedianTimeSource) error {
	for _, checkFunc := range v.checkSanityFunctions {
		if err := checkFunc.Handler(block, powLimit, timeSource); err != nil {
			return errors.New("[powCheckBlockSanity] error:" + err.Error())
		}
	}
	return nil
}
func (v *Validator) CheckBlockContextFunctions(block *types.Block) error {
	for _, checkFunc := range v.checkContextFunctions {
		if err := checkFunc.Handler(block); err != nil {
			return errors.New("[CheckBlockContext] error:" + err.Error())
		}
	}
	return nil
}
func (v *Validator) CheckBlockContext(block *types.Block, prevNode *BlockNode) (err error) {
	header := block.Header
	if prevNode == nil {
		return nil
	}
	expectedDifficulty, err := v.chain.CalcNextRequiredDifficulty(
		prevNode, time.Unix(int64(header.GetTimeStamp()), 0))
	if err != nil {
		return err
	}
	if header.GetBits() != expectedDifficulty {
		return errors.New("[powCheckBlockContext] block difficulty is not the expected")
	}
	medianTime := CalcPastMedianTime(prevNode)
	tempTime := time.Unix(int64(header.GetTimeStamp()), 0)
	if !tempTime.After(medianTime) {
		return errors.New("[powCheckBlockContext] block timestamp is not after expected")
	}
	if err := v.CheckBlockContextFunctions(block); err != nil {
		return err
	}
	blockHeight := prevNode.Height + 1
	for _, txn := range block.Transactions[1:] {
		if err := CheckTransactionFinalize(txn, blockHeight); err != nil {
			return errors.New("[powCheckBlockContext] block contains unfinalized transaction")
		}
	}
	return nil
}