github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/bft/backend/snapshot.go (about) 1 package backend 2 3 import ( 4 "bytes" 5 "encoding/json" 6 7 "github.com/quickchainproject/quickchain/common" 8 "github.com/quickchainproject/quickchain/consensus/bft" 9 "github.com/quickchainproject/quickchain/consensus/bft/validator" 10 "github.com/quickchainproject/quickchain/core/types" 11 "github.com/quickchainproject/quickchain/qctdb" 12 ) 13 14 const ( 15 dbKeySnapshotPrefix = "bft-snapshot" 16 ) 17 18 // Vote represents a single vote that an authorized validator made to modify the 19 // list of authorizations. 20 type Vote struct { 21 Validator common.Address `json:"validator"` // Authorized validator that cast this vote 22 Block uint64 `json:"block"` // Block number the vote was cast in (expire old votes) 23 Address common.Address `json:"address"` // Account being voted on to change its authorization 24 Authorize bool `json:"authorize"` // Whether to authorize or deauthorize the voted account 25 } 26 27 // Tally is a simple vote tally to keep the current score of votes. Votes that 28 // go against the proposal aren't counted since it's equivalent to not voting. 29 type Tally struct { 30 Authorize bool `json:"authorize"` // Whether the vote it about authorizing or kicking someone 31 Votes int `json:"votes"` // Number of votes until now wanting to pass the proposal 32 } 33 34 // Snapshot is the state of the authorization voting at a given point in time. 35 type Snapshot struct { 36 Epoch uint64 // The number of blocks after which to checkpoint and reset the pending votes 37 38 Number uint64 // Block number where the snapshot was created 39 Hash common.Hash // Block hash where the snapshot was created 40 Votes []*Vote // List of votes cast in chronological order 41 Tally map[common.Address]Tally // Current vote tally to avoid recalculating 42 ValSet bft.ValidatorSet // Set of authorized validators at this moment 43 } 44 45 // newSnapshot create a new snapshot with the specified startup parameters. This 46 // method does not initialize the set of recent validators, so only ever use if for 47 // the genesis block. 48 func newSnapshot(epoch uint64, number uint64, hash common.Hash, valSet bft.ValidatorSet) *Snapshot { 49 snap := &Snapshot{ 50 Epoch: epoch, 51 Number: number, 52 Hash: hash, 53 ValSet: valSet, 54 Tally: make(map[common.Address]Tally), 55 } 56 return snap 57 } 58 59 // loadSnapshot loads an existing snapshot from the database. 60 func loadSnapshot(epoch uint64, db qctdb.Database, hash common.Hash) (*Snapshot, error) { 61 blob, err := db.Get(append([]byte(dbKeySnapshotPrefix), hash[:]...)) 62 if err != nil { 63 return nil, err 64 } 65 snap := new(Snapshot) 66 if err := json.Unmarshal(blob, snap); err != nil { 67 return nil, err 68 } 69 snap.Epoch = epoch 70 71 return snap, nil 72 } 73 74 // store inserts the snapshot into the database. 75 func (s *Snapshot) store(db qctdb.Database) error { 76 blob, err := json.Marshal(s) 77 if err != nil { 78 return err 79 } 80 return db.Put(append([]byte(dbKeySnapshotPrefix), s.Hash[:]...), blob) 81 } 82 83 // copy creates a deep copy of the snapshot, though not the individual votes. 84 func (s *Snapshot) copy() *Snapshot { 85 cpy := &Snapshot{ 86 Epoch: s.Epoch, 87 Number: s.Number, 88 Hash: s.Hash, 89 ValSet: s.ValSet.Copy(), 90 Votes: make([]*Vote, len(s.Votes)), 91 Tally: make(map[common.Address]Tally), 92 } 93 94 for address, tally := range s.Tally { 95 cpy.Tally[address] = tally 96 } 97 copy(cpy.Votes, s.Votes) 98 99 return cpy 100 } 101 102 // checkVote return whether it's a valid vote 103 func (s *Snapshot) checkVote(address common.Address, authorize bool) bool { 104 _, validator := s.ValSet.GetByAddress(address) 105 return (validator != nil && !authorize) || (validator == nil && authorize) 106 } 107 108 // cast adds a new vote into the tally. 109 func (s *Snapshot) cast(address common.Address, authorize bool) bool { 110 // Ensure the vote is meaningful 111 if !s.checkVote(address, authorize) { 112 return false 113 } 114 // Cast the vote into an existing or new tally 115 if old, ok := s.Tally[address]; ok { 116 old.Votes++ 117 s.Tally[address] = old 118 } else { 119 s.Tally[address] = Tally{Authorize: authorize, Votes: 1} 120 } 121 return true 122 } 123 124 // uncast removes a previously cast vote from the tally. 125 func (s *Snapshot) uncast(address common.Address, authorize bool) bool { 126 // If there's no tally, it's a dangling vote, just drop 127 tally, ok := s.Tally[address] 128 if !ok { 129 return false 130 } 131 // Ensure we only revert counted votes 132 if tally.Authorize != authorize { 133 return false 134 } 135 // Otherwise revert the vote 136 if tally.Votes > 1 { 137 tally.Votes-- 138 s.Tally[address] = tally 139 } else { 140 delete(s.Tally, address) 141 } 142 return true 143 } 144 145 // apply creates a new authorization snapshot by applying the given headers to 146 // the original one. 147 func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { 148 // Allow passing in no headers for cleaner code 149 if len(headers) == 0 { 150 return s, nil 151 } 152 // Sanity check that the headers can be applied 153 for i := 0; i < len(headers)-1; i++ { 154 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 155 return nil, errInvalidVotingChain 156 } 157 } 158 if headers[0].Number.Uint64() != s.Number+1 { 159 return nil, errInvalidVotingChain 160 } 161 // Iterate through the headers and create a new snapshot 162 snap := s.copy() 163 164 for _, header := range headers { 165 // Remove any votes on checkpoint blocks 166 number := header.Number.Uint64() 167 if number%s.Epoch == 0 { 168 snap.Votes = nil 169 snap.Tally = make(map[common.Address]Tally) 170 } 171 // Resolve the authorization key and check against validators 172 validator, err := ecrecover(header) 173 if err != nil { 174 return nil, err 175 } 176 if _, v := snap.ValSet.GetByAddress(validator); v == nil { 177 return nil, errUnauthorized 178 } 179 180 // Header authorized, discard any previous votes from the validator 181 for i, vote := range snap.Votes { 182 if vote.Validator == validator && vote.Address == header.Coinbase { 183 // Uncast the vote from the cached tally 184 snap.uncast(vote.Address, vote.Authorize) 185 186 // Uncast the vote from the chronological list 187 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 188 break // only one vote allowed 189 } 190 } 191 // Tally up the new vote from the validator 192 var authorize bool 193 switch { 194 case bytes.Compare(header.Nonce[:], nonceAuthVote) == 0: 195 authorize = true 196 case bytes.Compare(header.Nonce[:], nonceDropVote) == 0: 197 authorize = false 198 default: 199 return nil, errInvalidVote 200 } 201 if snap.cast(header.Coinbase, authorize) { 202 snap.Votes = append(snap.Votes, &Vote{ 203 Validator: validator, 204 Block: number, 205 Address: header.Coinbase, 206 Authorize: authorize, 207 }) 208 } 209 // If the vote passed, update the list of validators 210 if tally := snap.Tally[header.Coinbase]; tally.Votes > snap.ValSet.Size()/2 { 211 if tally.Authorize { 212 snap.ValSet.AddValidator(header.Coinbase) 213 } else { 214 snap.ValSet.RemoveValidator(header.Coinbase) 215 216 // Discard any previous votes the deauthorized validator cast 217 for i := 0; i < len(snap.Votes); i++ { 218 if snap.Votes[i].Validator == header.Coinbase { 219 // Uncast the vote from the cached tally 220 snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize) 221 222 // Uncast the vote from the chronological list 223 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 224 225 i-- 226 } 227 } 228 } 229 // Discard any previous votes around the just changed account 230 for i := 0; i < len(snap.Votes); i++ { 231 if snap.Votes[i].Address == header.Coinbase { 232 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 233 i-- 234 } 235 } 236 delete(snap.Tally, header.Coinbase) 237 } 238 } 239 snap.Number += uint64(len(headers)) 240 snap.Hash = headers[len(headers)-1].Hash() 241 242 return snap, nil 243 } 244 245 // validators retrieves the list of authorized validators in ascending order. 246 func (s *Snapshot) validators() []common.Address { 247 validators := make([]common.Address, 0, s.ValSet.Size()) 248 for _, validator := range s.ValSet.List() { 249 validators = append(validators, validator.Address()) 250 } 251 for i := 0; i < len(validators); i++ { 252 for j := i + 1; j < len(validators); j++ { 253 if bytes.Compare(validators[i][:], validators[j][:]) > 0 { 254 validators[i], validators[j] = validators[j], validators[i] 255 } 256 } 257 } 258 return validators 259 } 260 261 type snapshotJSON struct { 262 Epoch uint64 `json:"epoch"` 263 Number uint64 `json:"number"` 264 Hash common.Hash `json:"hash"` 265 Votes []*Vote `json:"votes"` 266 Tally map[common.Address]Tally `json:"tally"` 267 268 // for validator set 269 Validators []common.Address `json:"validators"` 270 Policy bft.ProposerPolicy `json:"policy"` 271 } 272 273 func (s *Snapshot) toJSONStruct() *snapshotJSON { 274 return &snapshotJSON{ 275 Epoch: s.Epoch, 276 Number: s.Number, 277 Hash: s.Hash, 278 Votes: s.Votes, 279 Tally: s.Tally, 280 Validators: s.validators(), 281 Policy: s.ValSet.Policy(), 282 } 283 } 284 285 // Unmarshal from a json byte array 286 func (s *Snapshot) UnmarshalJSON(b []byte) error { 287 var j snapshotJSON 288 if err := json.Unmarshal(b, &j); err != nil { 289 return err 290 } 291 292 s.Epoch = j.Epoch 293 s.Number = j.Number 294 s.Hash = j.Hash 295 s.Votes = j.Votes 296 s.Tally = j.Tally 297 s.ValSet = validator.NewSet(j.Validators, j.Policy) 298 return nil 299 } 300 301 // Marshal to a json byte array 302 func (s *Snapshot) MarshalJSON() ([]byte, error) { 303 j := s.toJSONStruct() 304 return json.Marshal(j) 305 }