github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/consensus/dpos/dpos.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  package dpos
    10  
    11  import (
    12  	"bytes"
    13  	"encoding/binary"
    14  	"errors"
    15  	"fmt"
    16  	"math/big"
    17  	"sync"
    18  	"time"
    19  
    20  	"github.com/ethereum/go-ethereum/accounts"
    21  	"github.com/ethereum/go-ethereum/common"
    22  	"github.com/ethereum/go-ethereum/consensus"
    23  	"github.com/ethereum/go-ethereum/consensus/misc"
    24  	"github.com/ethereum/go-ethereum/core/state"
    25  	"github.com/ethereum/go-ethereum/core/types"
    26  	"github.com/ethereum/go-ethereum/crypto"
    27  	"github.com/ethereum/go-ethereum/crypto/sha3"
    28  	"github.com/ethereum/go-ethereum/ethdb"
    29  	"github.com/ethereum/go-ethereum/log"
    30  	"github.com/ethereum/go-ethereum/params"
    31  	"github.com/ethereum/go-ethereum/rlp"
    32  	"github.com/ethereum/go-ethereum/rpc"
    33  	"github.com/ethereum/go-ethereum/trie"
    34  	lru "github.com/hashicorp/golang-lru"
    35  )
    36  
    37  
    38  const (
    39  extraVanity        = 32   //固定为签名者虚荣保留的额外数据前缀字节数
    40  extraSeal          = 65   //固定为签名者密封保留的额外数据后缀字节数
    41  inmemorySignatures = 4096 //要保存在内存中的最近块签名数
    42  
    43  //blockinterval=int64(10)//出块间隔
    44  //epochinterval=int64(86400)//选举周期间隔24*60*60 s
    45  //最大验证大小=21
    46  //
    47  //conensusize=15//maxvalidatorsize*2/3+1
    48  blockInterval    = int64(10)  	//附带条件
    49  epochInterval    = int64(60)  //选举周间隔24*60*60 s
    50  	maxValidatorSize = 3
    51  safeSize         =  2	//maxvalidator大小*2/3+1
    52  consensusSize    =  2	//maxvalidator大小*2/3+1
    53  )
    54  
    55  
    56  
    57  var (
    58  	big0  = big.NewInt(0)
    59  	big8  = big.NewInt(8)
    60  	big32 = big.NewInt(32)
    61  
    62  frontierBlockReward  *big.Int = big.NewInt(5e+18) //
    63  byzantiumBlockReward *big.Int = big.NewInt(3e+18) //从拜占庭向上成功开采一个区块,在魏城获得区块奖励
    64  
    65  	timeOfFirstBlock = int64(0)
    66  
    67  	confirmedBlockHead = []byte("confirmed-block-head")
    68  )
    69  
    70  var (
    71  //当请求块的签名者列表时,返回errunknownblock。
    72  //这不是本地区块链的一部分。
    73  	errUnknownBlock = errors.New("unknown block")
    74  //如果块的额外数据节短于
    75  //32字节,这是存储签名者虚荣所必需的。
    76  	errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing")
    77  //如果块的额外数据节似乎不存在,则返回errmissingsignature
    78  //包含65字节的secp256k1签名。
    79  	errMissingSignature = errors.New("extra-data 65 byte suffix signature missing")
    80  //如果块的mix digest为非零,则返回errInvalidMixDigest。
    81  	errInvalidMixDigest = errors.New("non-zero mix digest")
    82  //如果块包含非空的叔叔列表,则返回errInvalidUncleHash。
    83  	errInvalidUncleHash  = errors.New("non empty uncle hash")
    84  	errInvalidDifficulty = errors.New("invalid difficulty")
    85  
    86  //如果块的时间戳低于,则返回errInvalidTimestamp
    87  //上一个块的时间戳+最小块周期。
    88  	ErrInvalidTimestamp           = errors.New("invalid timestamp")
    89  	ErrWaitForPrevBlock           = errors.New("wait for last block arrived")
    90  	ErrMintFutureBlock            = errors.New("mint the future block")
    91  	ErrMismatchSignerAndValidator = errors.New("mismatch block signer and validator")
    92  	ErrInvalidBlockValidator      = errors.New("invalid block validator")
    93  	ErrInvalidMintBlockTime       = errors.New("invalid time to mint the block")
    94  	ErrNilBlockHeader             = errors.New("nil block header returned")
    95  )
    96  var (
    97  uncleHash = types.CalcUncleHash(nil) //作为叔叔,Keccak256(rlp([])在POW之外总是毫无意义的。
    98  )
    99  
   100  type Dpos struct {
   101  config *params.DposConfig //共识引擎配置参数
   102  db      ethdb.Database     //存储和检索快照检查点的数据库
   103  
   104  	signer               common.Address
   105  	signFn               SignerFn
   106  signatures           *lru.ARCCache //加快开采速度的近期区块特征
   107  	confirmedBlockHeader *types.Header
   108  
   109  	mu   sync.RWMutex
   110  	stop chan bool
   111  }
   112  
   113  type SignerFn func(accounts.Account, []byte) ([]byte, error)
   114  
   115  //注:Sighash是从集团复制的
   116  //sighash返回用作权限证明输入的哈希
   117  //签署。它是除65字节签名之外的整个头的哈希
   118  //包含在额外数据的末尾。
   119  //
   120  //注意,该方法要求额外数据至少为65字节,否则
   121  //恐慌。这样做是为了避免意外使用这两个表单(存在签名
   122  //或者不是),这可能会被滥用,从而为同一个头产生不同的散列。
   123  func sigHash(header *types.Header) (hash common.Hash) {
   124  	hasher := sha3.NewKeccak256()
   125  
   126  	rlp.Encode(hasher, []interface{}{
   127  		header.ParentHash,
   128  		header.UncleHash,
   129  		header.Validator,
   130  		header.Coinbase,
   131  		header.Root,
   132  		header.TxHash,
   133  		header.ReceiptHash,
   134  		header.Bloom,
   135  		header.Difficulty,
   136  		header.Number,
   137  		header.GasLimit,
   138  		header.GasUsed,
   139  		header.Time,
   140  header.Extra[:len(header.Extra)-65], //是的,如果多余的太短,这会很恐慌的
   141  		header.MixDigest,
   142  		header.Nonce,
   143  		header.DposContext.Root(),
   144  header.MaxValidatorSize,			//
   145  	})
   146  	hasher.Sum(hash[:0])
   147  
   148  	return hash
   149  }
   150  
   151  func New(config *params.DposConfig, db ethdb.Database) *Dpos {
   152  	signatures, _ := lru.NewARC(inmemorySignatures)
   153  
   154  	return &Dpos{
   155  		config:     config,
   156  		db:         db,
   157  		signatures: signatures,
   158  	}
   159  }
   160  
   161  func (d *Dpos) Author(header *types.Header) (common.Address, error) {
   162  	return header.Validator, nil
   163  }
   164  
   165  //验证批量是否符合共识算法规则
   166  func (d *Dpos) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool, blockInterval uint64) error {
   167  	return d.verifyHeader(chain, header, nil, blockInterval)
   168  }
   169  
   170  func (d *Dpos) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header,blockInterval uint64 ) error {
   171  	if header.Number == nil {
   172  		return errUnknownBlock
   173  	}
   174  	number := header.Number.Uint64()
   175  //不需要验证功能块
   176  	if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
   177  		return consensus.ErrFutureBlock
   178  	}
   179  //检查额外数据是否包含虚荣和签名
   180  	if len(header.Extra) < extraVanity {
   181  		return errMissingVanity
   182  	}
   183  	if len(header.Extra) < extraVanity+extraSeal {
   184  		return errMissingSignature
   185  	}
   186  //确保混合摘要为零,因为我们当前没有分叉保护
   187  	if header.MixDigest != (common.Hash{}) {
   188  		return errInvalidMixDigest
   189  	}
   190  //困难总是1
   191  //度设定为1
   192  //
   193  	if header.Difficulty.Uint64() != 1 {		
   194  		return errInvalidDifficulty
   195  	}
   196  
   197  //确保块中不包含任何在DPO中无意义的叔叔。
   198  	if header.UncleHash != uncleHash {
   199  		return errInvalidUncleHash
   200  	}
   201  //如果所有检查都通过,则验证硬分叉的任何特殊字段
   202  	if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
   203  		return err
   204  	}
   205  
   206  	var parent *types.Header
   207  	if len(parents) > 0 {
   208  		parent = parents[len(parents)-1]
   209  	} else {
   210  		parent = chain.GetHeader(header.ParentHash, number-1)
   211  	}
   212  	if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
   213  		return consensus.ErrUnknownAncestor
   214  	}
   215  	if parent.Time.Uint64()+blockInterval> header.Time.Uint64() {
   216  		return ErrInvalidTimestamp
   217  	}
   218  	return nil
   219  }
   220  
   221  //批量验证区块头是否符合公共计算法规
   222  func (d *Dpos) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool,) (chan<- struct{}, <-chan error) {
   223  	abort := make(chan struct{})
   224  	results := make(chan error, len(headers))
   225  	blockInterval := chain.GetHeaderByNumber(0).BlockInterval
   226  
   227  	go func() {
   228  		for i, header := range headers {
   229  //header.extra=make([]字节,ExtraVanity+ExtraSeal)
   230  			err := d.verifyHeader(chain, header, headers[:i],blockInterval)
   231  			select {
   232  			case <-abort:
   233  				return
   234  			case results <- err:
   235  			}
   236  		}
   237  	}()
   238  	return abort, results
   239  }
   240  
   241  //verifyuncles实现converse.engine,始终返回任何
   242  //因为这个共识机制不允许叔叔。
   243  func (d *Dpos) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
   244  	if len(block.Uncles()) > 0 {
   245  		return errors.New("uncles not allowed")
   246  	}
   247  	return nil
   248  }
   249  
   250  //验证seal是否执行consension.engine,检查签名是否包含
   251  //头部满足共识协议要求。
   252  func (d *Dpos) VerifySeal(chain consensus.ChainReader, currentheader, genesisheader *types.Header) error {
   253  	return d.verifySeal(chain, currentheader, genesisheader,nil)
   254  }
   255  
   256  func (d *Dpos) verifySeal(chain consensus.ChainReader, currentheader, genesisheader *types.Header, parents []*types.Header) error {
   257  //验证不支持Genesis块
   258  	number := currentheader.Number.Uint64()
   259  	if number == 0 {
   260  		return errUnknownBlock
   261  	}
   262  	var parent *types.Header
   263  	if len(parents) > 0 {
   264  		parent = parents[len(parents)-1]
   265  	} else {
   266  		parent = chain.GetHeader(currentheader.ParentHash, number-1)
   267  	}
   268  
   269  	trieDB := trie.NewDatabase(d.db)
   270  dposContext, err := types.NewDposContextFromProto(trieDB, parent.DposContext) //零位
   271  
   272  	if err != nil {
   273  		return err
   274  	}
   275  	epochContext := &EpochContext{DposContext: dposContext}
   276  	blockInterVal := genesisheader.BlockInterval
   277  	validator, err := epochContext.lookupValidator(currentheader.Time.Int64(),blockInterVal)
   278  	if err != nil {
   279  		return err
   280  	}
   281  //
   282  	if err := d.verifyBlockSigner(validator, currentheader); err != nil {
   283  		return err
   284  	}
   285  	return d.updateConfirmedBlockHeader(chain)
   286  }
   287  
   288  func (d *Dpos) verifyBlockSigner(validator common.Address, header *types.Header) error {
   289  	signer, err := ecrecover(header, d.signatures)
   290  	if err != nil {
   291  		return err
   292  	}
   293  	if bytes.Compare(signer.Bytes(), validator.Bytes()) != 0 {
   294  		return ErrInvalidBlockValidator
   295  	}
   296  	if bytes.Compare(signer.Bytes(), header.Validator.Bytes()) != 0 {
   297  		return ErrMismatchSignerAndValidator
   298  	}
   299  	return nil
   300  }
   301  
   302  func (d *Dpos) updateConfirmedBlockHeader(chain consensus.ChainReader) error {
   303  	if d.confirmedBlockHeader == nil {
   304  		header, err := d.loadConfirmedBlockHeader(chain)
   305  		if err != nil {
   306  			header = chain.GetHeaderByNumber(0)
   307  			if header == nil {
   308  				return err
   309  			}
   310  		}
   311  		d.confirmedBlockHeader = header
   312  	}
   313  
   314  	curHeader := chain.CurrentHeader()
   315  
   316  	fmt.Println("+++++++++++++++++++555555++++++++++++++++++++++\n")
   317  	genesisHeader := chain.GetHeaderByNumber(0)
   318  	fmt.Println("+++++++++++++++++++from genesisBlock to get Maxvalidatorsize++++++++++++++++++++++\n")
   319  	epoch := int64(-1)
   320  	validatorMap := make(map[common.Address]bool)
   321  	for d.confirmedBlockHeader.Hash() != curHeader.Hash() &&
   322  		d.confirmedBlockHeader.Number.Uint64() < curHeader.Number.Uint64() {
   323  		curEpoch := curHeader.Time.Int64() / epochInterval
   324  		if curEpoch != epoch {
   325  			epoch = curEpoch
   326  			validatorMap = make(map[common.Address]bool)
   327  		}
   328  //快速返回
   329  //如果块数差小于一致同意的见证数
   330  //无需检查是否确认阻塞
   331  		consensusSize :=int(genesisHeader.MaxValidatorSize*2/3+1)
   332  		if curHeader.Number.Int64()-d.confirmedBlockHeader.Number.Int64() < int64(consensusSize-len(validatorMap)) {
   333  			log.Debug("Dpos fast return", "current", curHeader.Number.String(), "confirmed", d.confirmedBlockHeader.Number.String(), "witnessCount", len(validatorMap))
   334  			return nil
   335  		}
   336  		validatorMap[curHeader.Validator] = true
   337  		if len(validatorMap) >= consensusSize {
   338  			d.confirmedBlockHeader = curHeader
   339  			if err := d.storeConfirmedBlockHeader(d.db); err != nil {
   340  				return err
   341  			}
   342  			log.Debug("dpos set confirmed block header success", "currentHeader", curHeader.Number.String())
   343  			return nil
   344  		}
   345  		curHeader = chain.GetHeaderByHash(curHeader.ParentHash)
   346  		if curHeader == nil {
   347  			return ErrNilBlockHeader
   348  		}
   349  	}
   350  	return nil
   351  }
   352  
   353  func (s *Dpos) loadConfirmedBlockHeader(chain consensus.ChainReader) (*types.Header, error) {
   354  	key, err := s.db.Get(confirmedBlockHead)
   355  	if err != nil {
   356  		return nil, err
   357  	}
   358  	header := chain.GetHeaderByHash(common.BytesToHash(key))
   359  	if header == nil {
   360  		return nil, ErrNilBlockHeader
   361  	}
   362  	return header, nil
   363  }
   364  
   365  //存储将快照插入数据库。
   366  func (s *Dpos) storeConfirmedBlockHeader(db ethdb.Database) error {
   367  	return db.Put(confirmedBlockHead, s.confirmedBlockHeader.Hash().Bytes())
   368  }
   369  
   370  func (d *Dpos) Prepare(chain consensus.ChainReader, header *types.Header) error {
   371  	header.Nonce = types.BlockNonce{}
   372  	number := header.Number.Uint64()
   373  	if len(header.Extra) < extraVanity {
   374  		header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
   375  	}
   376  	header.Extra = header.Extra[:extraVanity]
   377  	header.Extra = append(header.Extra, make([]byte, extraSeal)...)
   378  	parent := chain.GetHeader(header.ParentHash, number-1)
   379  	if parent == nil {
   380  		return consensus.ErrUnknownAncestor
   381  	}
   382  	header.Difficulty = d.CalcDifficulty(chain, header.Time.Uint64(), parent)
   383  	header.Validator = d.signer
   384  	return nil
   385  }
   386  
   387  func AccumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
   388  //根据链进程选择正确的区块奖励
   389  	blockReward := frontierBlockReward
   390  	if config.IsByzantium(header.Number) {
   391  		blockReward = byzantiumBlockReward
   392  	}
   393  //为矿工和任何包括叔叔的人累积奖励
   394  	reward := new(big.Int).Set(blockReward)
   395  	state.AddBalance(header.Coinbase, reward)
   396  }
   397  
   398  //将出块周期内的交易打包进新的区域块中
   399  func (d *Dpos) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
   400  	uncles []*types.Header, receipts []*types.Receipt, dposContext *types.DposContext) (*types.Block, error) {
   401  //累积积木奖励并提交最终状态根
   402  	AccumulateRewards(chain.Config(), state, header, uncles)
   403  	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   404  
   405  	parent := chain.GetHeaderByHash(header.ParentHash)
   406  	epochContext := &EpochContext{
   407  		statedb:     state,
   408  		DposContext: dposContext,
   409  		TimeStamp:   header.Time.Int64(),
   410  	}
   411  	if timeOfFirstBlock == 0 {
   412  		if firstBlockHeader := chain.GetHeaderByNumber(1); firstBlockHeader != nil {
   413  			timeOfFirstBlock = firstBlockHeader.Time.Int64()
   414  		}
   415  	}
   416  	fmt.Println("++++++++++++++77777++++++++++++++++++\n")
   417  	fmt.Println("**************get genesis header********\n")
   418  	genesis := chain.GetHeaderByNumber(0)
   419  
   420  	err := epochContext.tryElect(genesis, parent)
   421  	if err != nil {
   422  		return nil, fmt.Errorf("got error when elect next epoch, err: %s", err)
   423  	}
   424  
   425  //更新薄荷计数trie
   426  	updateMintCnt(parent.Time.Int64(), header.Time.Int64(), header.Validator, dposContext)
   427  	header.DposContext = dposContext.ToProto()
   428  	return types.NewBlock(header, txs, uncles, receipts), nil
   429  }
   430  
   431  func (d *Dpos) checkDeadline(lastBlock *types.Block, now int64, blockInterval uint64) error {
   432  	prevSlot := PrevSlot(now, blockInterval)
   433  	nextSlot := NextSlot(now, blockInterval)
   434  	if lastBlock.Time().Int64() >= nextSlot {
   435  		return ErrMintFutureBlock
   436  	}
   437  //最后一个街区到了,或者时间到了
   438  	if lastBlock.Time().Int64() == prevSlot || nextSlot-now <= 1 {
   439  		return nil
   440  	}
   441  	return ErrWaitForPrevBlock
   442  }
   443  
   444  //检查当前的验证人员是否在当前的节点上
   445  func (d *Dpos) CheckValidator(lastBlock *types.Block, now int64,blockInterval uint64) error {
   446  	if err := d.checkDeadline(lastBlock, now, blockInterval); err != nil {
   447  		return err
   448  	}
   449  //
   450  	dposContext, err := types.NewDposContextFromProto(trie.NewDatabase(d.db), lastBlock.Header().DposContext)
   451  	if err != nil {
   452  		return err
   453  	}
   454  	epochContext := &EpochContext{DposContext: dposContext}
   455  	validator, err := epochContext.lookupValidator(now,blockInterval)
   456  	if err != nil {
   457  		return err
   458  	}
   459  	if (validator == common.Address{}) || bytes.Compare(validator.Bytes(), d.signer.Bytes()) != 0 {
   460  		return ErrInvalidBlockValidator
   461  	}
   462  	return nil
   463  }
   464  
   465  //Seal使用本地矿工的
   466  //密封顶部。
   467  //验证模块内容是否符合DPOSS计算法规(验证新模块是否应由该验证人员提出模块)
   468  func (d *Dpos) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) {
   469  	header := block.Header()
   470  	number := header.Number.Uint64()
   471  //不支持密封Genesis块
   472  	if number == 0 {
   473  		return nil, errUnknownBlock
   474  	}
   475  	now := time.Now().Unix()
   476  	delay := NextSlot(now,chain.GetHeaderByNumber(0).BlockInterval) - now
   477  	if delay > 0 {
   478  		select {
   479  		case <-stop:
   480  			return nil, nil
   481  		case <-time.After(time.Duration(delay) * time.Second):
   482  		}
   483  	}
   484  	block.Header().Time.SetInt64(time.Now().Unix())
   485  
   486  //时间到了,在街区签名
   487  //对新块进行签名
   488  	sighash, err := d.signFn(accounts.Account{Address: d.signer}, sigHash(header).Bytes())
   489  	if err != nil {
   490  		return nil, err
   491  	}
   492  	copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
   493  	return block.WithSeal(header), nil
   494  }
   495  
   496  func (d *Dpos) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
   497  	return big.NewInt(1)
   498  }
   499  
   500  func (d *Dpos) APIs(chain consensus.ChainReader) []rpc.API {
   501  	return []rpc.API{{
   502  		Namespace: "dpos",
   503  		Version:   "1.0",
   504  		Service:   &API{chain: chain, dpos: d},
   505  		Public:    true,
   506  	}}
   507  }
   508  
   509  func (d *Dpos) Authorize(signer common.Address, signFn SignerFn) {
   510  	d.mu.Lock()
   511  	d.signer = signer
   512  	d.signFn = signFn
   513  	d.mu.Unlock()
   514  }
   515  
   516  func (d *Dpos) Close() error {
   517  	return nil
   518  }
   519  
   520  //ecrecover从签名的头中提取以太坊帐户地址。
   521  func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
   522  //如果签名已经缓存,则返回
   523  	hash := header.Hash()
   524  	if address, known := sigcache.Get(hash); known {
   525  		return address.(common.Address), nil
   526  	}
   527  //从头中检索签名额外数据
   528  	if len(header.Extra) < extraSeal {
   529  		return common.Address{}, errMissingSignature
   530  	}
   531  	signature := header.Extra[len(header.Extra)-extraSeal:]
   532  //恢复公钥和以太坊地址
   533  	pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature)
   534  	if err != nil {
   535  		return common.Address{}, err
   536  	}
   537  	var signer common.Address
   538  	copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
   539  	sigcache.Add(hash, signer)
   540  	return signer, nil
   541  }
   542  
   543  func PrevSlot(now int64, blockInterval uint64) int64 {
   544  	return int64((now-1)/int64(blockInterval)) * int64(blockInterval)
   545  }
   546  
   547  func NextSlot(now int64, blockInterval uint64) int64 {
   548  	return int64((now+int64(blockInterval)-1)/int64(blockInterval)) * int64(blockInterval)
   549  }
   550  
   551  //更新Newblock矿工的mintcntrie计数
   552  //更新周期内验证人员出块数目的
   553  func updateMintCnt(parentBlockTime, currentBlockTime int64, validator common.Address, dposContext *types.DposContext) {
   554  	currentMintCntTrie := dposContext.MintCntTrie()
   555  	currentEpoch := parentBlockTime / epochInterval
   556  	currentEpochBytes := make([]byte, 8)
   557  	binary.BigEndian.PutUint64(currentEpochBytes, uint64(currentEpoch))
   558  
   559  	cnt := int64(1)
   560  	newEpoch := currentBlockTime / epochInterval
   561  //仍在当前报告期间
   562  	if currentEpoch == newEpoch {
   563  		iter := trie.NewIterator(currentMintCntTrie.NodeIterator(currentEpochBytes))
   564  
   565  //当电流不是起源时,从mintcntrie读取最后一个计数。
   566  		if iter.Next() {
   567  			cntBytes := currentMintCntTrie.Get(append(currentEpochBytes, validator.Bytes()...))
   568  
   569  //不是第一次造币
   570  			if cntBytes != nil {
   571  				cnt = int64(binary.BigEndian.Uint64(cntBytes)) + 1
   572  			}
   573  		}
   574  	}
   575  
   576  	newCntBytes := make([]byte, 8)
   577  	newEpochBytes := make([]byte, 8)
   578  	binary.BigEndian.PutUint64(newEpochBytes, uint64(newEpoch))
   579  	binary.BigEndian.PutUint64(newCntBytes, uint64(cnt))
   580  	dposContext.MintCntTrie().TryUpdate(append(newEpochBytes, validator.Bytes()...), newCntBytes)
   581  }