gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/consensus/parlia/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 parlia 18 19 import ( 20 "bytes" 21 "encoding/hex" 22 "encoding/json" 23 "errors" 24 "math/big" 25 "sort" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/consensus" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/ethdb" 31 "github.com/ethereum/go-ethereum/internal/ethapi" 32 "github.com/ethereum/go-ethereum/log" 33 "github.com/ethereum/go-ethereum/params" 34 lru "github.com/hashicorp/golang-lru" 35 ) 36 37 // Snapshot is the state of the validatorSet at a given point. 38 type Snapshot struct { 39 config *params.ParliaConfig // Consensus engine parameters to fine tune behavior 40 ethAPI *ethapi.PublicBlockChainAPI 41 sigCache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover 42 43 Number uint64 `json:"number"` // Block number where the snapshot was created 44 Hash common.Hash `json:"hash"` // Block hash where the snapshot was created 45 Validators map[common.Address]struct{} `json:"validators"` // Set of authorized validators at this moment 46 Recents map[uint64]common.Address `json:"recents"` // Set of recent validators for spam protections 47 RecentForkHashes map[uint64]string `json:"recent_fork_hashes"` // Set of recent forkHash 48 } 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 it for 52 // the genesis block. 53 func newSnapshot( 54 config *params.ParliaConfig, 55 sigCache *lru.ARCCache, 56 number uint64, 57 hash common.Hash, 58 validators []common.Address, 59 ethAPI *ethapi.PublicBlockChainAPI, 60 ) *Snapshot { 61 snap := &Snapshot{ 62 config: config, 63 ethAPI: ethAPI, 64 sigCache: sigCache, 65 Number: number, 66 Hash: hash, 67 Recents: make(map[uint64]common.Address), 68 RecentForkHashes: make(map[uint64]string), 69 Validators: make(map[common.Address]struct{}), 70 } 71 for _, v := range validators { 72 snap.Validators[v] = struct{}{} 73 } 74 return snap 75 } 76 77 // validatorsAscending implements the sort interface to allow sorting a list of addresses 78 type validatorsAscending []common.Address 79 80 func (s validatorsAscending) Len() int { return len(s) } 81 func (s validatorsAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 } 82 func (s validatorsAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 83 84 // loadSnapshot loads an existing snapshot from the database. 85 func loadSnapshot(config *params.ParliaConfig, sigCache *lru.ARCCache, db ethdb.Database, hash common.Hash, ethAPI *ethapi.PublicBlockChainAPI) (*Snapshot, error) { 86 blob, err := db.Get(append([]byte("parlia-"), hash[:]...)) 87 if err != nil { 88 return nil, err 89 } 90 snap := new(Snapshot) 91 if err := json.Unmarshal(blob, snap); err != nil { 92 return nil, err 93 } 94 snap.config = config 95 snap.sigCache = sigCache 96 snap.ethAPI = ethAPI 97 98 return snap, nil 99 } 100 101 // store inserts the snapshot into the database. 102 func (s *Snapshot) store(db ethdb.Database) error { 103 blob, err := json.Marshal(s) 104 if err != nil { 105 return err 106 } 107 return db.Put(append([]byte("parlia-"), s.Hash[:]...), blob) 108 } 109 110 // copy creates a deep copy of the snapshot 111 func (s *Snapshot) copy() *Snapshot { 112 cpy := &Snapshot{ 113 config: s.config, 114 ethAPI: s.ethAPI, 115 sigCache: s.sigCache, 116 Number: s.Number, 117 Hash: s.Hash, 118 Validators: make(map[common.Address]struct{}), 119 Recents: make(map[uint64]common.Address), 120 RecentForkHashes: make(map[uint64]string), 121 } 122 123 for v := range s.Validators { 124 cpy.Validators[v] = struct{}{} 125 } 126 for block, v := range s.Recents { 127 cpy.Recents[block] = v 128 } 129 for block, id := range s.RecentForkHashes { 130 cpy.RecentForkHashes[block] = id 131 } 132 return cpy 133 } 134 135 func (s *Snapshot) isMajorityFork(forkHash string) bool { 136 ally := 0 137 for _, h := range s.RecentForkHashes { 138 if h == forkHash { 139 ally++ 140 } 141 } 142 return ally > len(s.RecentForkHashes)/2 143 } 144 145 // apply creates a new authorization snapshot by applying the given headers to the original one 146 func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainReader, parents []*types.Header, chainId *big.Int) (*Snapshot, error) { 147 // Allow passing in no headers for cleaner code 148 if len(headers) == 0 { 149 return s, nil 150 } 151 // Sanity check that the headers can be applied 152 for i := 0; i < len(headers)-1; i++ { 153 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 154 return nil, errOutOfRangeChain 155 } 156 if !bytes.Equal(headers[i+1].ParentHash.Bytes(), headers[i].Hash().Bytes()) { 157 return nil, errBlockHashInconsistent 158 } 159 } 160 if headers[0].Number.Uint64() != s.Number+1 { 161 return nil, errOutOfRangeChain 162 } 163 if !bytes.Equal(headers[0].ParentHash.Bytes(), s.Hash.Bytes()) { 164 return nil, errBlockHashInconsistent 165 } 166 // Iterate through the headers and create a new snapshot 167 snap := s.copy() 168 169 for _, header := range headers { 170 number := header.Number.Uint64() 171 // Delete the oldest validator from the recent list to allow it signing again 172 if limit := uint64(len(snap.Validators)/2 + 1); number >= limit { 173 delete(snap.Recents, number-limit) 174 } 175 if limit := uint64(len(snap.Validators)); number >= limit { 176 delete(snap.RecentForkHashes, number-limit) 177 } 178 // Resolve the authorization key and check against signers 179 validator, err := ecrecover(header, s.sigCache, chainId) 180 if err != nil { 181 return nil, err 182 } 183 if _, ok := snap.Validators[validator]; !ok { 184 return nil, errUnauthorizedValidator 185 } 186 for _, recent := range snap.Recents { 187 if recent == validator { 188 return nil, errRecentlySigned 189 } 190 } 191 snap.Recents[number] = validator 192 // change validator set 193 offset := uint64(len(snap.Validators) / 2) 194 if number > 0 && number%s.config.Epoch == offset { 195 checkpointHeader := FindAncientHeader(header, offset, chain, parents) 196 if checkpointHeader == nil { 197 return nil, consensus.ErrUnknownAncestor 198 } 199 if len(checkpointHeader.Extra) >= extraVanity+extraSeal { 200 validatorBytes := checkpointHeader.Extra[extraVanity : len(checkpointHeader.Extra)-extraSeal] 201 // get validators from headers and use that for new validator set 202 newValArr, err := ParseValidators(validatorBytes) 203 if err != nil { 204 return nil, err 205 } 206 newVals := make(map[common.Address]struct{}, len(newValArr)) 207 for _, val := range newValArr { 208 newVals[val] = struct{}{} 209 } 210 oldLimit := len(snap.Validators)/2 + 1 211 newLimit := len(newVals)/2 + 1 212 if newLimit < oldLimit { 213 for i := 0; i < oldLimit-newLimit; i++ { 214 delete(snap.Recents, number-uint64(newLimit)-uint64(i)) 215 } 216 } 217 oldLimit = len(snap.Validators) 218 newLimit = len(newVals) 219 if newLimit < oldLimit { 220 for i := 0; i < oldLimit-newLimit; i++ { 221 delete(snap.RecentForkHashes, number-uint64(newLimit)-uint64(i)) 222 } 223 } 224 snap.Validators = newVals 225 } else { 226 // this can potentially happen one time only for a new chain, if the most recent epoch block was pre-fork 227 // this entirely depends on which block number the fork occurs along with the parlia.epoch config 228 log.Warn("Skipping validator rotation: epoch header malformed", "number", number, "epoch", checkpointHeader.Number) 229 } 230 } 231 snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity]) 232 } 233 snap.Number += uint64(len(headers)) 234 snap.Hash = headers[len(headers)-1].Hash() 235 return snap, nil 236 } 237 238 // validators retrieves the list of validators in ascending order. 239 func (s *Snapshot) validators() []common.Address { 240 validators := make([]common.Address, 0, len(s.Validators)) 241 for v := range s.Validators { 242 validators = append(validators, v) 243 } 244 sort.Sort(validatorsAscending(validators)) 245 return validators 246 } 247 248 // inturn returns if a validator at a given block height is in-turn or not. 249 func (s *Snapshot) inturn(validator common.Address) bool { 250 validators := s.validators() 251 offset := (s.Number + 1) % uint64(len(validators)) 252 return validators[offset] == validator 253 } 254 255 func (s *Snapshot) indexOfVal(validator common.Address) int { 256 validators := s.validators() 257 for idx, val := range validators { 258 if val == validator { 259 return idx 260 } 261 } 262 return -1 263 } 264 265 func (s *Snapshot) supposeValidator() common.Address { 266 validators := s.validators() 267 index := (s.Number + 1) % uint64(len(validators)) 268 return validators[index] 269 } 270 271 func ParseValidators(validatorsBytes []byte) ([]common.Address, error) { 272 if len(validatorsBytes)%validatorBytesLength != 0 { 273 return nil, errors.New("invalid validators bytes") 274 } 275 n := len(validatorsBytes) / validatorBytesLength 276 result := make([]common.Address, n) 277 for i := 0; i < n; i++ { 278 address := make([]byte, validatorBytesLength) 279 copy(address, validatorsBytes[i*validatorBytesLength:(i+1)*validatorBytesLength]) 280 result[i] = common.BytesToAddress(address) 281 } 282 return result, nil 283 } 284 285 func FindAncientHeader(header *types.Header, ite uint64, chain consensus.ChainReader, candidateParents []*types.Header) *types.Header { 286 ancient := header 287 for i := uint64(1); i <= ite; i++ { 288 parentHash := ancient.ParentHash 289 parentHeight := ancient.Number.Uint64() - 1 290 found := false 291 if len(candidateParents) > 0 { 292 index := sort.Search(len(candidateParents), func(i int) bool { 293 return candidateParents[i].Number.Uint64() >= parentHeight 294 }) 295 if index < len(candidateParents) && candidateParents[index].Number.Uint64() == parentHeight && 296 candidateParents[index].Hash() == parentHash { 297 ancient = candidateParents[index] 298 found = true 299 } 300 } 301 if !found { 302 ancient = chain.GetHeader(parentHash, parentHeight) 303 found = true 304 } 305 if ancient == nil || !found { 306 return nil 307 } 308 } 309 return ancient 310 }