github.com/gilgames000/kcc-geth@v1.0.6/consensus/posa/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 posa 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "sort" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/consensus" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/ethdb" 28 "github.com/ethereum/go-ethereum/params" 29 lru "github.com/hashicorp/golang-lru" 30 ) 31 32 // Snapshot is the state of the authorization voting at a given point in time. 33 type Snapshot struct { 34 config *params.POSAConfig // Consensus engine parameters to fine tune behavior 35 sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover 36 37 Number uint64 `json:"number"` // Block number where the snapshot was created 38 Hash common.Hash `json:"hash"` // Block hash where the snapshot was created 39 Validators map[common.Address]struct{} `json:"validators"` // Set of authorized validators at this moment 40 Recents map[uint64]common.Address `json:"recents"` // Set of recent validators for spam protections 41 } 42 43 // validatorsAscending implements the sort interface to allow sorting a list of addresses 44 type validatorsAscending []common.Address 45 46 func (s validatorsAscending) Len() int { return len(s) } 47 func (s validatorsAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 } 48 func (s validatorsAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 49 50 // newSnapshot creates a new snapshot with the specified startup parameters. This 51 // method does not initialize the set of recent validators, so only ever use if for 52 // the genesis block. 53 func newSnapshot(config *params.POSAConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, validators []common.Address) *Snapshot { 54 snap := &Snapshot{ 55 config: config, 56 sigcache: sigcache, 57 Number: number, 58 Hash: hash, 59 Validators: make(map[common.Address]struct{}), 60 Recents: make(map[uint64]common.Address), 61 } 62 for _, validator := range validators { 63 snap.Validators[validator] = struct{}{} 64 } 65 return snap 66 } 67 68 // loadSnapshot loads an existing snapshot from the database. 69 func loadSnapshot(config *params.POSAConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) { 70 blob, err := db.Get(append([]byte("congress-"), hash[:]...)) 71 if err != nil { 72 return nil, err 73 } 74 snap := new(Snapshot) 75 if err := json.Unmarshal(blob, snap); err != nil { 76 return nil, err 77 } 78 snap.config = config 79 snap.sigcache = sigcache 80 81 return snap, nil 82 } 83 84 // store inserts the snapshot into the database. 85 func (s *Snapshot) store(db ethdb.Database) error { 86 blob, err := json.Marshal(s) 87 if err != nil { 88 return err 89 } 90 return db.Put(append([]byte("congress-"), s.Hash[:]...), blob) 91 } 92 93 // copy creates a deep copy of the snapshot, though not the individual votes. 94 func (s *Snapshot) copy() *Snapshot { 95 cpy := &Snapshot{ 96 config: s.config, 97 sigcache: s.sigcache, 98 Number: s.Number, 99 Hash: s.Hash, 100 Validators: make(map[common.Address]struct{}), 101 Recents: make(map[uint64]common.Address), 102 } 103 for validator := range s.Validators { 104 cpy.Validators[validator] = struct{}{} 105 } 106 for block, validator := range s.Recents { 107 cpy.Recents[block] = validator 108 } 109 110 return cpy 111 } 112 113 // apply creates a new authorization snapshot by applying the given headers to 114 // the original one. 115 func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderReader, parents []*types.Header) (*Snapshot, error) { 116 // Allow passing in no headers for cleaner code 117 if len(headers) == 0 { 118 return s, nil 119 } 120 // Sanity check that the headers can be applied 121 for i := 0; i < len(headers)-1; i++ { 122 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 123 return nil, errInvalidVotingChain 124 } 125 } 126 if headers[0].Number.Uint64() != s.Number+1 { 127 return nil, errInvalidVotingChain 128 } 129 // Iterate through the headers and create a new snapshot 130 snap := s.copy() 131 132 for _, header := range headers { 133 // Remove any votes on checkpoint blocks 134 number := header.Number.Uint64() 135 // Delete the oldest validator from the recent list to allow it signing again 136 if limit := uint64(len(snap.Validators)/2 + 1); number >= limit { 137 delete(snap.Recents, number-limit) 138 } 139 // Resolve the authorization key and check against validators 140 validator, err := ecrecover(header, s.sigcache) 141 if err != nil { 142 return nil, err 143 } 144 if _, ok := snap.Validators[validator]; !ok { 145 return nil, errUnauthorizedValidator 146 } 147 for _, recent := range snap.Recents { 148 if recent == validator { 149 return nil, errRecentlySigned 150 } 151 } 152 snap.Recents[number] = validator 153 154 // update validators at the first block at epoch 155 if number > 0 && number%s.config.Epoch == 0 { 156 checkpointHeader := header 157 158 // get validators from headers and use that for new validator set 159 validators := make([]common.Address, (len(checkpointHeader.Extra)-extraVanity-extraSeal)/common.AddressLength) 160 for i := 0; i < len(validators); i++ { 161 copy(validators[i][:], checkpointHeader.Extra[extraVanity+i*common.AddressLength:]) 162 } 163 164 newValidators := make(map[common.Address]struct{}) 165 for _, validator := range validators { 166 newValidators[validator] = struct{}{} 167 } 168 169 // need to delete recorded recent seen blocks if necessary, it may pause whole chain when validators length 170 // decreases. 171 limit := uint64(len(newValidators)/2 + 1) 172 for i := 0; i < len(snap.Validators)/2-len(newValidators)/2; i++ { 173 delete(snap.Recents, number-limit-uint64(i)) 174 } 175 176 snap.Validators = newValidators 177 } 178 } 179 180 snap.Number += uint64(len(headers)) 181 snap.Hash = headers[len(headers)-1].Hash() 182 183 return snap, nil 184 } 185 186 // validators retrieves the list of authorized validators in ascending order. 187 func (s *Snapshot) validators() []common.Address { 188 sigs := make([]common.Address, 0, len(s.Validators)) 189 for sig := range s.Validators { 190 sigs = append(sigs, sig) 191 } 192 sort.Sort(validatorsAscending(sigs)) 193 return sigs 194 } 195 196 // inturn returns if a validator at a given block height is in-turn or not. 197 func (s *Snapshot) inturn(number uint64, validator common.Address) bool { 198 validators, offset := s.validators(), 0 199 for offset < len(validators) && validators[offset] != validator { 200 offset++ 201 } 202 return (number % uint64(len(validators))) == uint64(offset) 203 }