// Snapshot is the state of the authorization voting at a given point in time.type Snapshot struct {
config *params.CliqueConfig // Consensus engine parameters to fine tune behavior
sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover
Number uint64`json:"number"`// Block number where the snapshot was created
Hash common.Hash `json:"hash"`// Block hash where the snapshot was created
Signers map[common.Address]struct{} `json:"signers"`// Set of authorized signers at this moment
Recents map[uint64]common.Address `json:"recents"`// Set of recent signers for spam protections
Votes []*Vote `json:"votes"`// List of votes cast in chronological order
Tally map[common.Address]Tally `json:"tally"`// Current vote tally to avoid recalculating
}
func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-chanstruct{}) (*types.Block, error) {
...
number := header.Number.Uint64()
...
signer, signFn := c.signer, c.signFn
...
// Bail out if we're unauthorized to sign a block
snap, err := c.snapshot(chain, number-1, header.ParentHash, nil)
...
// If we're amongst the recent signers, wait for the next blockfor seen, recent := range snap.Recents {
if recent == signer {
// Signer is among recents, only wait if the current block doesn't shift it outif limit := uint64(len(snap.Signers)/2 + 1); number < limit || seen > number-limit {
log.Info("Signed recently, must wait for others")
<-stop
returnnil, nil
}
}
}
...
}
// validVote returns whether it makes sense to cast the specified vote in the// given snapshot context (e.g. don't try to add an already authorized signer).func (s *Snapshot) validVote(address common.Address, authorize bool) bool {
_, signer := s.Signers[address]
return (signer && !authorize) || (!signer && authorize)
}
func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
...
snap := s.copy()
for _, header := range headers {
// Remove any votes on checkpoint blocks
number := header.Number.Uint64()
if number%s.config.Epoch == 0 {
snap.Votes = nil
snap.Tally = make(map[common.Address]Tally)
}
...
signer, err := ecrecover(header, s.sigcache)
...
// If the vote passed, update the list of signersif tally := snap.Tally[header.Coinbase]; tally.Votes > len(snap.Signers)/2 {
if tally.Authorize {
snap.Signers[header.Coinbase] = struct{}{}
} else {
delete(snap.Signers, header.Coinbase)
...
}
}
}
...
}