github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/consensus/clique/snapshot.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package clique 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "sort" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/core/types" 26 "github.com/ethereum/go-ethereum/ethdb" 27 "github.com/ethereum/go-ethereum/log" 28 "github.com/ethereum/go-ethereum/params" 29 lru "github.com/hashicorp/golang-lru" 30 ) 31 32 // Vote represents a single vote that an authorized signer made to modify the 33 // list of authorizations. 34 type Vote struct { 35 Signer common.Address `json:"signer"` // Authorized signer that cast this vote 36 Block uint64 `json:"block"` // Block number the vote was cast in (expire old votes) 37 Address common.Address `json:"address"` // Account being voted on to change its authorization 38 Authorize bool `json:"authorize"` // Whether to authorize or deauthorize the voted account 39 } 40 41 // Tally is a simple vote tally to keep the current score of votes. Votes that 42 // go against the proposal aren't counted since it's equivalent to not voting. 43 type Tally struct { 44 Authorize bool `json:"authorize"` // Whether the vote is about authorizing or kicking someone 45 Votes int `json:"votes"` // Number of votes until now wanting to pass the proposal 46 } 47 48 // Snapshot is the state of the authorization voting at a given point in time. 49 type Snapshot struct { 50 config *params.CliqueConfig // Consensus engine parameters to fine tune behavior 51 sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover 52 53 Number uint64 `json:"number"` // Block number where the snapshot was created 54 Hash common.Hash `json:"hash"` // Block hash where the snapshot was created 55 Signers map[common.Address]struct{} `json:"signers"` // Set of authorized signers at this moment 56 Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections 57 Votes []*Vote `json:"votes"` // List of votes cast in chronological order 58 Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating 59 } 60 61 // signersAscending implements the sort interface to allow sorting a list of addresses 62 type signersAscending []common.Address 63 64 func (s signersAscending) Len() int { return len(s) } 65 func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 } 66 func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 67 68 // newSnapshot creates a new snapshot with the specified startup parameters. This 69 // method does not initialize the set of recent signers, so only ever use if for 70 // the genesis block. 71 func newSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, signers []common.Address) *Snapshot { 72 snap := &Snapshot{ 73 config: config, 74 sigcache: sigcache, 75 Number: number, 76 Hash: hash, 77 Signers: make(map[common.Address]struct{}), 78 Recents: make(map[uint64]common.Address), 79 Tally: make(map[common.Address]Tally), 80 } 81 for _, signer := range signers { 82 snap.Signers[signer] = struct{}{} 83 } 84 return snap 85 } 86 87 // loadSnapshot loads an existing snapshot from the database. 88 func loadSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) { 89 blob, err := db.Get(append([]byte("clique-"), hash[:]...)) 90 if err != nil { 91 return nil, err 92 } 93 snap := new(Snapshot) 94 if err := json.Unmarshal(blob, snap); err != nil { 95 return nil, err 96 } 97 snap.config = config 98 snap.sigcache = sigcache 99 100 return snap, nil 101 } 102 103 // store inserts the snapshot into the database. 104 func (s *Snapshot) store(db ethdb.Database) error { 105 blob, err := json.Marshal(s) 106 if err != nil { 107 return err 108 } 109 return db.Put(append([]byte("clique-"), s.Hash[:]...), blob) 110 } 111 112 // copy creates a deep copy of the snapshot, though not the individual votes. 113 func (s *Snapshot) copy() *Snapshot { 114 cpy := &Snapshot{ 115 config: s.config, 116 sigcache: s.sigcache, 117 Number: s.Number, 118 Hash: s.Hash, 119 Signers: make(map[common.Address]struct{}), 120 Recents: make(map[uint64]common.Address), 121 Votes: make([]*Vote, len(s.Votes)), 122 Tally: make(map[common.Address]Tally), 123 } 124 for signer := range s.Signers { 125 cpy.Signers[signer] = struct{}{} 126 } 127 for block, signer := range s.Recents { 128 cpy.Recents[block] = signer 129 } 130 for address, tally := range s.Tally { 131 cpy.Tally[address] = tally 132 } 133 copy(cpy.Votes, s.Votes) 134 135 return cpy 136 } 137 138 // validVote returns whether it makes sense to cast the specified vote in the 139 // given snapshot context (e.g. don't try to add an already authorized signer). 140 func (s *Snapshot) validVote(address common.Address, authorize bool) bool { 141 _, signer := s.Signers[address] 142 return (signer && !authorize) || (!signer && authorize) 143 } 144 145 // cast adds a new vote into the tally. 146 func (s *Snapshot) cast(address common.Address, authorize bool) bool { 147 // Ensure the vote is meaningful 148 if !s.validVote(address, authorize) { 149 return false 150 } 151 // Cast the vote into an existing or new tally 152 if old, ok := s.Tally[address]; ok { 153 old.Votes++ 154 s.Tally[address] = old 155 } else { 156 s.Tally[address] = Tally{Authorize: authorize, Votes: 1} 157 } 158 return true 159 } 160 161 // uncast removes a previously cast vote from the tally. 162 func (s *Snapshot) uncast(address common.Address, authorize bool) bool { 163 // If there's no tally, it's a dangling vote, just drop 164 tally, ok := s.Tally[address] 165 if !ok { 166 return false 167 } 168 // Ensure we only revert counted votes 169 if tally.Authorize != authorize { 170 return false 171 } 172 // Otherwise revert the vote 173 if tally.Votes > 1 { 174 tally.Votes-- 175 s.Tally[address] = tally 176 } else { 177 delete(s.Tally, address) 178 } 179 return true 180 } 181 182 // apply creates a new authorization snapshot by applying the given headers to 183 // the original one. 184 func (s *Snapshot) apply(headers []*types.Header, fullHeaderChainAvailable bool) (*Snapshot, error) { 185 // Allow passing in no headers for cleaner code 186 if len(headers) == 0 { 187 return s, nil 188 } 189 // Sanity check that the headers can be applied 190 for i := 0; i < len(headers)-1; i++ { 191 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 192 log.Warn("Error occurred while applying snapshot", "err", errInvalidVotingChain, 193 "prev number", headers[i].Number.Uint64(), 194 "next number", headers[i+1].Number.Uint64()) 195 return nil, errInvalidVotingChain 196 } 197 } 198 if fullHeaderChainAvailable { 199 if headers[0].Number.Uint64() != s.Number+1 { 200 log.Warn("Error occurred while applying snapshot", "err", errInvalidVotingChain, 201 "prev number", s.Number, 202 "next number", headers[0].Number.Uint64()) 203 return nil, errInvalidVotingChain 204 } 205 } 206 207 // Iterate through the headers and create a new snapshot 208 snap := s.copy() 209 210 for _, header := range headers { 211 // Remove any votes on checkpoint blocks 212 number := header.Number.Uint64() 213 if number%s.config.Epoch == 0 { 214 snap.Votes = nil 215 snap.Tally = make(map[common.Address]Tally) 216 } 217 // Delete the oldest signer from the recent list to allow it signing again 218 if limit := uint64(len(snap.Signers)/2 + 1); number >= limit { 219 delete(snap.Recents, number-limit) 220 } 221 // Resolve the authorization key and check against signers 222 signer, err := ecrecover(header, s.sigcache) 223 if err != nil { 224 return nil, err 225 } 226 if _, ok := snap.Signers[signer]; !ok { 227 return nil, errUnauthorizedSigner 228 } 229 for _, recent := range snap.Recents { 230 if recent == signer { 231 return nil, errRecentlySigned 232 } 233 } 234 snap.Recents[number] = signer 235 236 proposedSigner := ProposedSigner(header.Extra) 237 // Header authorized, discard any previous votes from the signer 238 for i, vote := range snap.Votes { 239 if vote.Signer == signer && vote.Address == proposedSigner { 240 // Uncast the vote from the cached tally 241 snap.uncast(vote.Address, vote.Authorize) 242 243 // Uncast the vote from the chronological list 244 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 245 break // only one vote allowed 246 } 247 } 248 // Tally up the new vote from the signer 249 var authorize bool 250 switch { 251 case bytes.Equal(header.Nonce[:], nonceAuthVote): 252 authorize = true 253 case bytes.Equal(header.Nonce[:], nonceDropVote): 254 authorize = false 255 default: 256 return nil, errInvalidVote 257 } 258 if snap.cast(proposedSigner, authorize) { 259 snap.Votes = append(snap.Votes, &Vote{ 260 Signer: signer, 261 Block: number, 262 Address: proposedSigner, 263 Authorize: authorize, 264 }) 265 } 266 // If the vote passed, update the list of signers 267 if tally := snap.Tally[proposedSigner]; tally.Votes > len(snap.Signers)/2 { 268 if tally.Authorize { 269 snap.Signers[proposedSigner] = struct{}{} 270 } else { 271 delete(snap.Signers, proposedSigner) 272 273 // Signer list shrunk, delete any leftover recent caches 274 if limit := uint64(len(snap.Signers)/2 + 1); number >= limit { 275 delete(snap.Recents, number-limit) 276 } 277 // Discard any previous votes the deauthorized signer cast 278 for i := 0; i < len(snap.Votes); i++ { 279 if snap.Votes[i].Signer == proposedSigner { 280 // Uncast the vote from the cached tally 281 snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize) 282 283 // Uncast the vote from the chronological list 284 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 285 286 i-- 287 } 288 } 289 } 290 // Discard any previous votes around the just changed account 291 for i := 0; i < len(snap.Votes); i++ { 292 if snap.Votes[i].Address == proposedSigner { 293 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 294 i-- 295 } 296 } 297 delete(snap.Tally, proposedSigner) 298 } 299 } 300 snap.Number += uint64(len(headers)) 301 snap.Hash = headers[len(headers)-1].Hash() 302 303 return snap, nil 304 } 305 306 // signers retrieves the list of authorized signers in ascending order. 307 func (s *Snapshot) signers() []common.Address { 308 sigs := make([]common.Address, 0, len(s.Signers)) 309 for sig := range s.Signers { 310 sigs = append(sigs, sig) 311 } 312 sort.Sort(signersAscending(sigs)) 313 return sigs 314 } 315 316 // inturn returns if a signer at a given block height is in-turn or not. 317 func (s *Snapshot) inturn(number uint64, signer common.Address) bool { 318 signers, offset := s.signers(), 0 319 for offset < len(signers) && signers[offset] != signer { 320 offset++ 321 } 322 return (number % uint64(len(signers))) == uint64(offset) 323 }