OSDN Git Service

3ea6220d8f11cdf05e9143a5bedae77771701d55
[bytom/vapor.git] / consensus / consensus / dpos / dpos.go
1 package dpos
2
3 import (
4         "bytes"
5         "encoding/json"
6         "errors"
7         "math/big"
8         "sync"
9         "time"
10
11         lru "github.com/hashicorp/golang-lru"
12         log "github.com/sirupsen/logrus"
13         "github.com/vapor/chain"
14         "github.com/vapor/common"
15         "github.com/vapor/config"
16         "github.com/vapor/consensus"
17         "github.com/vapor/crypto"
18         "github.com/vapor/crypto/ed25519/chainkd"
19         "github.com/vapor/protocol"
20         "github.com/vapor/protocol/bc"
21         "github.com/vapor/protocol/bc/types"
22         "github.com/vapor/protocol/vm/vmutil"
23 )
24
25 const (
26         inMemorySnapshots  = 128             // Number of recent vote snapshots to keep in memory
27         inMemorySignatures = 4096            // Number of recent block signatures to keep in memory
28         secondsPerYear     = 365 * 24 * 3600 // Number of seconds for one year
29         checkpointInterval = 360             // About N hours if config.period is N
30         module             = "dpos"
31 )
32
33 //delegated-proof-of-stake protocol constants.
34 var (
35         SignerBlockReward     = big.NewInt(5e+18) // Block reward in wei for successfully mining a block first year
36         defaultEpochLength    = uint64(3000000)   // Default number of blocks after which vote's period of validity
37         defaultBlockPeriod    = uint64(3)         // Default minimum difference between two consecutive block's timestamps
38         defaultMaxSignerCount = uint64(21)        //
39         //defaultMinVoterBalance           = new(big.Int).Mul(big.NewInt(10000), big.NewInt(1e+18))
40         defaultMinVoterBalance           = uint64(0)
41         extraVanity                      = 32            // Fixed number of extra-data prefix bytes reserved for signer vanity
42         extraSeal                        = 65            // Fixed number of extra-data suffix bytes reserved for signer seal
43         defaultDifficulty                = big.NewInt(1) // Default difficulty
44         defaultLoopCntRecalculateSigners = uint64(10)    // Default loop count to recreate signers from top tally
45         minerRewardPerThousand           = uint64(618)   // Default reward for miner in each block from block reward (618/1000)
46         candidateNeedPD                  = false         // is new candidate need Proposal & Declare process
47 )
48
49 var (
50         // errUnknownBlock is returned when the list of signers is requested for a block
51         // that is not part of the local blockchain.
52         errUnknownBlock = errors.New("unknown block")
53
54         // errMissingVanity is returned if a block's extra-data section is shorter than
55         // 32 bytes, which is required to store the signer vanity.
56         errMissingVanity = errors.New("extra-data 32 byte vanity prefix missing")
57
58         // errMissingSignature is returned if a block's extra-data section doesn't seem
59         // to contain a 65 byte secp256k1 signature.
60         errMissingSignature = errors.New("extra-data 65 byte suffix signature missing")
61
62         // errInvalidMixDigest is returned if a block's mix digest is non-zero.
63         errInvalidMixDigest = errors.New("non-zero mix digest")
64
65         // errInvalidUncleHash is returned if a block contains an non-empty uncle list.
66         errInvalidUncleHash = errors.New("non empty uncle hash")
67
68         // ErrInvalidTimestamp is returned if the timestamp of a block is lower than
69         // the previous block's timestamp + the minimum block period.
70         ErrInvalidTimestamp = errors.New("invalid timestamp")
71
72         // errInvalidVotingChain is returned if an authorization list is attempted to
73         // be modified via out-of-range or non-contiguous headers.
74         errInvalidVotingChain = errors.New("invalid voting chain")
75
76         // errUnauthorized is returned if a header is signed by a non-authorized entity.
77         errUnauthorized = errors.New("unauthorized")
78
79         // errPunishedMissing is returned if a header calculate punished signer is wrong.
80         errPunishedMissing = errors.New("punished signer missing")
81
82         // errWaitTransactions is returned if an empty block is attempted to be sealed
83         // on an instant chain (0 second period). It's important to refuse these as the
84         // block reward is zero, so an empty block just bloats the chain... fast.
85         errWaitTransactions = errors.New("waiting for transactions")
86
87         // errUnclesNotAllowed is returned if uncles exists
88         errUnclesNotAllowed = errors.New("uncles not allowed")
89
90         // errCreateSignerQueueNotAllowed is returned if called in (block number + 1) % maxSignerCount != 0
91         errCreateSignerQueueNotAllowed = errors.New("create signer queue not allowed")
92
93         // errInvalidSignerQueue is returned if verify SignerQueue fail
94         errInvalidSignerQueue = errors.New("invalid signer queue")
95
96         // errSignerQueueEmpty is returned if no signer when calculate
97         errSignerQueueEmpty = errors.New("signer queue is empty")
98 )
99
100 type Dpos struct {
101         config     *config.DposConfig // Consensus engine configuration parameters
102         store      protocol.Store     // Database to store and retrieve snapshot checkpoints
103         recents    *lru.ARCCache      // Snapshots for recent block to speed up reorgs
104         signatures *lru.ARCCache      // Signatures of recent blocks to speed up mining
105         signer     string             // Ethereum address of the signing key
106         signFn     SignerFn           // Signer function to authorize hashes with
107         signTxFn   SignTxFn           // Sign transaction function to sign tx
108         lock       sync.RWMutex       // Protects the signer fields
109         lcsc       uint64             // Last confirmed side chain
110 }
111
112 // SignerFn is a signer callback function to request a hash to be signed by a backing account.
113 type SignerFn func(string, []byte) ([]byte, error)
114
115 // SignTxFn is a signTx
116 type SignTxFn func(string, *bc.Tx, *big.Int) (*bc.Tx, error)
117
118 //
119 func ecrecover(header *types.BlockHeader, sigcache *lru.ARCCache, c chain.Chain) (string, error) {
120
121         xpub := &chainkd.XPub{}
122         xpub.UnmarshalText(header.Coinbase)
123         derivedPK := xpub.PublicKey()
124         pubHash := crypto.Ripemd160(derivedPK)
125         address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
126         if err != nil {
127                 return "", err
128         }
129
130         return address.EncodeAddress(), nil
131 }
132
133 //
134 func New(config *config.DposConfig, store protocol.Store) *Dpos {
135         conf := *config
136         if conf.Epoch == 0 {
137                 conf.Epoch = defaultEpochLength
138         }
139         if conf.Period == 0 {
140                 conf.Period = defaultBlockPeriod
141         }
142         if conf.MaxSignerCount == 0 {
143                 conf.MaxSignerCount = defaultMaxSignerCount
144         }
145         if conf.MinVoterBalance == 0 {
146                 conf.MinVoterBalance = defaultMinVoterBalance
147         }
148         // Allocate the snapshot caches and create the engine
149         recents, _ := lru.NewARC(inMemorySnapshots)
150         signatures, _ := lru.NewARC(inMemorySignatures)
151         return &Dpos{
152                 config:     &conf,
153                 store:      store,
154                 recents:    recents,
155                 signatures: signatures,
156         }
157 }
158
159 // Authorize injects a private key into the consensus engine to mint new blocks with.
160 func (d *Dpos) Authorize(signer string /*, signFn SignerFn*/) {
161         d.lock.Lock()
162         defer d.lock.Unlock()
163
164         d.signer = signer
165         //d.signFn = signFn
166 }
167
168 // 从BLockHeader中获取到地址
169 func (d *Dpos) Author(header *types.BlockHeader, c chain.Chain) (string, error) {
170         return ecrecover(header, d.signatures, c)
171 }
172
173 func (d *Dpos) VerifyHeader(c chain.Chain, header *types.BlockHeader, seal bool) error {
174         return d.verifyCascadingFields(c, header, nil)
175 }
176
177 func (d *Dpos) VerifyHeaders(c chain.Chain, headers []*types.BlockHeader, seals []bool) (chan<- struct{}, <-chan error) {
178         return nil, nil
179 }
180
181 func (d *Dpos) VerifySeal(c chain.Chain, header *types.BlockHeader) error {
182         return nil
183 }
184
185 func (d *Dpos) verifyHeader(c chain.Chain, header *types.BlockHeader, parents []*types.BlockHeader) error {
186         return nil
187 }
188
189 func (d *Dpos) verifyCascadingFields(c chain.Chain, header *types.BlockHeader, parents []*types.BlockHeader) error {
190         // The genesis block is the always valid dead-end
191         height := header.Height
192         if height == 0 {
193                 return nil
194         }
195
196         var (
197                 parent *types.BlockHeader
198                 err    error
199         )
200
201         if len(parents) > 0 {
202                 parent = parents[len(parents)-1]
203         } else {
204                 parent, err = c.GetHeaderByHeight(height - 1)
205                 if err != nil {
206                         return err
207                 }
208         }
209
210         if parent == nil {
211                 return errors.New("unknown ancestor")
212         }
213
214         if _, err = d.snapshot(c, height-1, header.PreviousBlockHash, parents, nil, defaultLoopCntRecalculateSigners); err != nil {
215                 return err
216         }
217
218         return d.verifySeal(c, header, parents)
219 }
220
221 // verifySeal checks whether the signature contained in the header satisfies the
222 // consensus protocol requirements. The method accepts an optional list of parent
223 // headers that aren't yet part of the local blockchain to generate the snapshots
224 // from.
225 func (d *Dpos) verifySeal(c chain.Chain, header *types.BlockHeader, parents []*types.BlockHeader) error {
226         height := header.Height
227         if height == 0 {
228                 return errUnknownBlock
229         }
230         // Retrieve the snapshot needed to verify this header and cache it
231         snap, err := d.snapshot(c, height-1, header.PreviousBlockHash, parents, nil, defaultLoopCntRecalculateSigners)
232         if err != nil {
233                 return err
234         }
235
236         // Resolve the authorization key and check against signers
237         signer, err := ecrecover(header, d.signatures, c)
238         if err != nil {
239                 return err
240         }
241
242         if height > d.config.MaxSignerCount {
243                 var (
244                         parent *types.BlockHeader
245                         err    error
246                 )
247                 if len(parents) > 0 {
248                         parent = parents[len(parents)-1]
249                 } else {
250                         if parent, err = c.GetHeaderByHeight(height - 1); err != nil {
251                                 return err
252                         }
253                 }
254
255                 //parent
256                 xpub := &chainkd.XPub{}
257                 xpub.UnmarshalText(parent.Coinbase)
258                 derivedPK := xpub.PublicKey()
259                 pubHash := crypto.Ripemd160(derivedPK)
260                 parentCoinbase, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
261                 if err != nil {
262                         return err
263                 }
264
265                 //current
266                 xpub.UnmarshalText(header.Coinbase)
267                 derivedPK = xpub.PublicKey()
268                 pubHash = crypto.Ripemd160(derivedPK)
269                 currentCoinbase, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
270                 if err != nil {
271                         return err
272                 }
273
274                 parentHeaderExtra := HeaderExtra{}
275                 if err = json.Unmarshal(parent.Extra[extraVanity:len(parent.Extra)-extraSeal], &parentHeaderExtra); err != nil {
276                         return err
277                 }
278
279                 currentHeaderExtra := HeaderExtra{}
280                 if err = json.Unmarshal(header.Extra[extraVanity:len(header.Extra)-extraSeal], &currentHeaderExtra); err != nil {
281                         return err
282                 }
283
284                 // verify signerqueue
285                 if height%d.config.MaxSignerCount == 0 {
286                         err := snap.verifySignerQueue(currentHeaderExtra.SignerQueue)
287                         if err != nil {
288                                 return err
289                         }
290
291                 } else {
292                         for i := 0; i < int(d.config.MaxSignerCount); i++ {
293                                 if parentHeaderExtra.SignerQueue[i] != currentHeaderExtra.SignerQueue[i] {
294                                         return errInvalidSignerQueue
295                                 }
296                         }
297                 }
298                 // verify missing signer for punish
299                 parentSignerMissing := getSignerMissing(parentCoinbase.EncodeAddress(), currentCoinbase.EncodeAddress(), parentHeaderExtra)
300                 if len(parentSignerMissing) != len(currentHeaderExtra.SignerMissing) {
301                         return errPunishedMissing
302                 }
303                 for i, signerMissing := range currentHeaderExtra.SignerMissing {
304                         if parentSignerMissing[i] != signerMissing {
305                                 return errPunishedMissing
306                         }
307                 }
308
309         }
310
311         if !snap.inturn(signer, header.Timestamp) {
312                 return errUnauthorized
313         }
314
315         return nil
316 }
317
318 // Prepare implements consensus.Engine, preparing all the consensus fields of the header for running the transactions on top.
319 func (d *Dpos) Prepare(c chain.Chain, header *types.BlockHeader) error {
320         if d.config.GenesisTimestamp < uint64(time.Now().Unix()) {
321                 return nil
322         }
323
324         if header.Height == 1 {
325                 for {
326                         delay := time.Unix(int64(d.config.GenesisTimestamp-2), 0).Sub(time.Now())
327                         if delay <= time.Duration(0) {
328                                 log.WithFields(log.Fields{"module": module, "time": time.Now()}).Info("Ready for seal block")
329                                 break
330                         } else if delay > time.Duration(d.config.Period)*time.Second {
331                                 delay = time.Duration(d.config.Period) * time.Second
332                         }
333                         log.WithFields(log.Fields{"module": module, "delay": time.Duration(time.Unix(int64(d.config.GenesisTimestamp-2), 0).Sub(time.Now()))}).Info("Waiting for seal block")
334                         select {
335                         case <-time.After(delay):
336                                 continue
337                         }
338                 }
339         }
340         return nil
341 }
342
343 func (d *Dpos) Finalize(c chain.Chain, header *types.BlockHeader, txs []*bc.Tx) error {
344         height := header.Height
345         parent, err := c.GetHeaderByHeight(height - 1)
346         if parent == nil {
347                 return err
348         }
349         //parent
350         var xpub chainkd.XPub
351         xpub.UnmarshalText(parent.Coinbase)
352         pubHash := crypto.Ripemd160(xpub.PublicKey())
353         parentCoinbase, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
354         if err != nil {
355                 return err
356         }
357
358         //current
359         xpub.UnmarshalText(header.Coinbase)
360         pubHash = crypto.Ripemd160(xpub.PublicKey())
361         currentCoinbase, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
362         if err != nil {
363                 return err
364         }
365
366         //header.Timestamp
367         t := new(big.Int).Add(new(big.Int).SetUint64(parent.Timestamp), new(big.Int).SetUint64(d.config.Period))
368         header.Timestamp = t.Uint64()
369
370         if header.Timestamp < uint64(time.Now().Unix()) {
371                 header.Timestamp = uint64(time.Now().Unix())
372         }
373
374         if len(header.Extra) < extraVanity {
375                 header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
376         }
377
378         header.Extra = header.Extra[:extraVanity]
379         // genesisVotes write direct into snapshot, which number is 1
380         var genesisVotes []*Vote
381         parentHeaderExtra := HeaderExtra{}
382         currentHeaderExtra := HeaderExtra{}
383         if height == 1 {
384                 alreadyVote := make(map[string]struct{})
385                 for _, voter := range d.config.SelfVoteSigners {
386                         if _, ok := alreadyVote[voter]; !ok {
387                                 genesisVotes = append(genesisVotes, &Vote{
388                                         Voter:     voter,
389                                         Candidate: voter,
390                                         Stake:     0,
391                                         //Stake:     state.GetBalance(voter),
392                                 })
393                                 alreadyVote[voter] = struct{}{}
394                         }
395                 }
396         } else {
397                 parentHeaderExtraByte := parent.Extra[extraVanity : len(parent.Extra)-extraSeal]
398                 if err := json.Unmarshal(parentHeaderExtraByte, &parentHeaderExtra); err != nil {
399                         return err
400                 }
401                 currentHeaderExtra.ConfirmedBlockNumber = parentHeaderExtra.ConfirmedBlockNumber
402                 currentHeaderExtra.SignerQueue = parentHeaderExtra.SignerQueue
403                 currentHeaderExtra.LoopStartTime = parentHeaderExtra.LoopStartTime
404                 currentHeaderExtra.SignerMissing = getSignerMissing(parentCoinbase.EncodeAddress(), currentCoinbase.EncodeAddress(), parentHeaderExtra)
405         }
406
407         // calculate votes write into header.extra
408         currentHeaderExtra, err = d.processCustomTx(currentHeaderExtra, c, header, txs)
409         if err != nil {
410                 return err
411         }
412         // Assemble the voting snapshot to check which votes make sense
413         snap, err := d.snapshot(c, height-1, header.PreviousBlockHash, nil, genesisVotes, defaultLoopCntRecalculateSigners)
414         if err != nil {
415                 return err
416         }
417
418         currentHeaderExtra.ConfirmedBlockNumber = snap.getLastConfirmedBlockNumber(currentHeaderExtra.CurrentBlockConfirmations).Uint64()
419         // write signerQueue in first header, from self vote signers in genesis block
420         if height == 1 {
421                 currentHeaderExtra.LoopStartTime = d.config.GenesisTimestamp
422                 for i := 0; i < int(d.config.MaxSignerCount); i++ {
423                         currentHeaderExtra.SignerQueue = append(currentHeaderExtra.SignerQueue, d.config.SelfVoteSigners[i%len(d.config.SelfVoteSigners)])
424                 }
425         }
426         if height%d.config.MaxSignerCount == 0 {
427                 //currentHeaderExtra.LoopStartTime = header.Time.Uint64()
428                 currentHeaderExtra.LoopStartTime = currentHeaderExtra.LoopStartTime + d.config.Period*d.config.MaxSignerCount
429                 // create random signersQueue in currentHeaderExtra by snapshot.Tally
430                 currentHeaderExtra.SignerQueue = []string{}
431                 newSignerQueue, err := snap.createSignerQueue()
432                 if err != nil {
433                         return err
434                 }
435
436                 currentHeaderExtra.SignerQueue = newSignerQueue
437
438         }
439         // encode header.extra
440         currentHeaderExtraEnc, err := json.Marshal(currentHeaderExtra)
441         if err != nil {
442                 return err
443         }
444         header.Extra = append(header.Extra, currentHeaderExtraEnc...)
445         header.Extra = append(header.Extra, make([]byte, extraSeal)...)
446         return nil
447 }
448
449 func (d *Dpos) Seal(c chain.Chain, block *types.Block) (*types.Block, error) {
450         header := block.BlockHeader
451         height := header.Height
452         if height == 0 {
453                 return nil, errUnknownBlock
454         }
455
456         if d.config.Period == 0 && len(block.Transactions) == 0 {
457                 return nil, errWaitTransactions
458         }
459         // Bail out if we're unauthorized to sign a block
460         snap, err := d.snapshot(c, height-1, header.PreviousBlockHash, nil, nil, defaultLoopCntRecalculateSigners)
461         if err != nil {
462                 return nil, err
463         }
464         if !snap.inturn(d.signer, header.Timestamp) {
465                 return nil, errUnauthorized
466         }
467
468         var xPrv chainkd.XPrv
469         if config.CommonConfig.Consensus.Dpos.XPrv == "" {
470                 return nil, errors.New("Signer is empty")
471         }
472         xPrv.UnmarshalText([]byte(config.CommonConfig.Consensus.Dpos.XPrv))
473         sign := xPrv.Sign(block.BlockCommitment.TransactionsMerkleRoot.Bytes())
474         pubHash := crypto.Ripemd160(xPrv.XPub().PublicKey())
475
476         control, err := vmutil.P2WPKHProgram([]byte(pubHash))
477         if err != nil {
478                 return nil, err
479         }
480
481         block.Proof = types.Proof{Sign: sign, ControlProgram: control}
482         return block, nil
483 }
484
485 func (d *Dpos) IsSealer(c chain.Chain, hash bc.Hash, header *types.BlockHeader, headerTime uint64) (bool, error) {
486         var (
487                 snap    *Snapshot
488                 headers []*types.BlockHeader
489         )
490         h := hash
491         height := header.Height
492         for snap == nil {
493                 // If an in-memory snapshot was found, use that
494                 if s, ok := d.recents.Get(h); ok {
495                         snap = s.(*Snapshot)
496                         break
497                 }
498                 // If an on-disk checkpoint snapshot can be found, use that
499                 if height%checkpointInterval == 0 {
500                         if s, err := loadSnapshot(d.config, d.signatures, d.store, h); err == nil {
501                                 log.WithFields(log.Fields{"func": "IsSealer", "number": height, "hash": h}).Warn("Loaded voting snapshot from disk")
502                                 snap = s
503                                 break
504                         } else {
505                                 log.Warn("loadSnapshot:", err)
506                         }
507                 }
508
509                 if height == 0 {
510                         genesis, err := c.GetHeaderByHeight(0)
511                         if err != nil {
512                                 return false, err
513                         }
514                         var genesisVotes []*Vote
515                         alreadyVote := make(map[string]struct{})
516                         for _, voter := range d.config.SelfVoteSigners {
517                                 if _, ok := alreadyVote[voter]; !ok {
518                                         genesisVotes = append(genesisVotes, &Vote{
519                                                 Voter:     voter,
520                                                 Candidate: voter,
521                                                 Stake:     0,
522                                                 //Stake:     state.GetBalance(voter),
523                                         })
524                                         alreadyVote[voter] = struct{}{}
525                                 }
526                         }
527                         snap = newSnapshot(d.config, d.signatures, genesis.Hash(), genesisVotes, defaultLoopCntRecalculateSigners)
528                         if err := snap.store(d.store); err != nil {
529                                 return false, err
530                         }
531                         log.Info("Stored genesis voting snapshot to disk")
532                         break
533                 }
534
535                 header, err := c.GetHeaderByHeight(height)
536                 if header == nil || err != nil {
537                         return false, errors.New("unknown ancestor")
538                 }
539
540                 height, h = height-1, header.PreviousBlockHash
541         }
542
543         snap, err := snap.apply(headers)
544         if err != nil {
545                 return false, err
546         }
547
548         d.recents.Add(snap.Hash, snap)
549
550         if snap != nil {
551                 loopIndex := int((headerTime-snap.LoopStartTime)/snap.config.Period) % len(snap.Signers)
552                 if loopIndex >= len(snap.Signers) {
553                         return false, nil
554                 } else if *snap.Signers[loopIndex] != d.signer {
555                         return false, nil
556
557                 }
558                 return true, nil
559         } else {
560                 return false, nil
561         }
562 }
563
564 // snapshot retrieves the authorization snapshot at a given point in time.
565 func (d *Dpos) snapshot(c chain.Chain, number uint64, hash bc.Hash, parents []*types.BlockHeader, genesisVotes []*Vote, lcrs uint64) (*Snapshot, error) {
566
567         var (
568                 headers []*types.BlockHeader
569                 snap    *Snapshot
570         )
571         h := hash
572
573         for snap == nil {
574                 // If an in-memory snapshot was found, use that
575                 if s, ok := d.recents.Get(h); ok {
576                         snap = s.(*Snapshot)
577                         break
578                 }
579                 // If an on-disk checkpoint snapshot can be found, use that
580                 if number%checkpointInterval == 0 {
581                         if s, err := loadSnapshot(d.config, d.signatures, d.store, h); err == nil {
582                                 log.WithFields(log.Fields{"number": number, "hash": h}).Warn("Loaded voting snapshot from disk")
583                                 snap = s
584                                 break
585                         }
586                 }
587                 if number == 0 {
588                         genesis, err := c.GetHeaderByHeight(0)
589                         if err != nil {
590                                 return nil, err
591                         }
592                         if err := d.VerifyHeader(c, genesis, false); err != nil {
593                                 return nil, err
594                         }
595
596                         snap = newSnapshot(d.config, d.signatures, genesis.Hash(), genesisVotes, lcrs)
597                         if err := snap.store(d.store); err != nil {
598                                 return nil, err
599                         }
600                         log.Info("Stored genesis voting snapshot to disk")
601                         break
602                 }
603                 var header *types.BlockHeader
604                 if len(parents) > 0 {
605                         header = parents[len(parents)-1]
606                         if header.Hash() != h || header.Height != number {
607                                 return nil, errors.New("unknown ancestor")
608                         }
609                         parents = parents[:len(parents)-1]
610                 } else {
611                         var err error
612                         header, err = c.GetHeaderByHeight(number)
613                         if header == nil || err != nil {
614                                 return nil, errors.New("unknown ancestor")
615                         }
616                 }
617                 headers = append(headers, header)
618                 number, h = number-1, header.PreviousBlockHash
619         }
620
621         // Previous snapshot found, apply any pending headers on top of it
622         for i := 0; i < len(headers)/2; i++ {
623                 headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i]
624         }
625         snap, err := snap.apply(headers)
626         if err != nil {
627                 return nil, err
628         }
629         d.recents.Add(snap.Hash, snap)
630
631         // If we've generated a new checkpoint snapshot, save to disk
632         if snap.Number%checkpointInterval == 0 && len(headers) > 0 {
633                 if err = snap.store(d.store); err != nil {
634                         return nil, err
635                 }
636                 log.Info("Stored voting snapshot to disk", "number", snap.Number, "hash", snap.Hash)
637         }
638         return snap, err
639 }
640
641 // Get the signer missing from last signer till header.Coinbase
642 func getSignerMissing(lastSigner string, currentSigner string, extra HeaderExtra) []string {
643
644         var signerMissing []string
645         recordMissing := false
646         for _, signer := range extra.SignerQueue {
647                 if signer == lastSigner {
648                         recordMissing = true
649                         continue
650                 }
651                 if signer == currentSigner {
652                         break
653                 }
654                 if recordMissing {
655                         signerMissing = append(signerMissing, signer)
656                 }
657         }
658         return signerMissing
659 }