github.com/bloxroute-labs/bor@v0.1.4/consensus/bor/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 bor 18 19 import ( 20 "bytes" 21 "encoding/json" 22 23 lru "github.com/hashicorp/golang-lru" 24 25 "github.com/maticnetwork/bor/common" 26 "github.com/maticnetwork/bor/core/types" 27 "github.com/maticnetwork/bor/ethdb" 28 "github.com/maticnetwork/bor/internal/ethapi" 29 "github.com/maticnetwork/bor/log" 30 "github.com/maticnetwork/bor/params" 31 ) 32 33 // Snapshot is the state of the authorization voting at a given point in time. 34 type Snapshot struct { 35 config *params.BorConfig // Consensus engine parameters to fine tune behavior 36 ethAPI *ethapi.PublicBlockChainAPI 37 sigcache *lru.ARCCache // Cache of recent block signatures to speed up ecrecover 38 39 Number uint64 `json:"number"` // Block number where the snapshot was created 40 Hash common.Hash `json:"hash"` // Block hash where the snapshot was created 41 ValidatorSet *ValidatorSet `json:"validatorSet"` // Validator set at this moment 42 Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections 43 } 44 45 // signersAscending implements the sort interface to allow sorting a list of addresses 46 type signersAscending []common.Address 47 48 func (s signersAscending) Len() int { return len(s) } 49 func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 } 50 func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 51 52 // newSnapshot creates a new snapshot with the specified startup parameters. This 53 // method does not initialize the set of recent signers, so only ever use if for 54 // the genesis block. 55 func newSnapshot( 56 config *params.BorConfig, 57 sigcache *lru.ARCCache, 58 number uint64, 59 hash common.Hash, 60 validators []*Validator, 61 ethAPI *ethapi.PublicBlockChainAPI, 62 ) *Snapshot { 63 snap := &Snapshot{ 64 config: config, 65 ethAPI: ethAPI, 66 sigcache: sigcache, 67 Number: number, 68 Hash: hash, 69 ValidatorSet: NewValidatorSet(validators), 70 Recents: make(map[uint64]common.Address), 71 } 72 return snap 73 } 74 75 // loadSnapshot loads an existing snapshot from the database. 76 func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash, ethAPI *ethapi.PublicBlockChainAPI) (*Snapshot, error) { 77 blob, err := db.Get(append([]byte("bor-"), hash[:]...)) 78 if err != nil { 79 return nil, err 80 } 81 snap := new(Snapshot) 82 if err := json.Unmarshal(blob, snap); err != nil { 83 return nil, err 84 } 85 snap.config = config 86 snap.sigcache = sigcache 87 snap.ethAPI = ethAPI 88 89 // update total voting power 90 snap.ValidatorSet.updateTotalVotingPower() 91 92 return snap, nil 93 } 94 95 // store inserts the snapshot into the database. 96 func (s *Snapshot) store(db ethdb.Database) error { 97 blob, err := json.Marshal(s) 98 if err != nil { 99 return err 100 } 101 return db.Put(append([]byte("bor-"), s.Hash[:]...), blob) 102 } 103 104 // copy creates a deep copy of the snapshot, though not the individual votes. 105 func (s *Snapshot) copy() *Snapshot { 106 cpy := &Snapshot{ 107 config: s.config, 108 ethAPI: s.ethAPI, 109 sigcache: s.sigcache, 110 Number: s.Number, 111 Hash: s.Hash, 112 ValidatorSet: s.ValidatorSet.Copy(), 113 Recents: make(map[uint64]common.Address), 114 } 115 for block, signer := range s.Recents { 116 cpy.Recents[block] = signer 117 } 118 119 return cpy 120 } 121 122 func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { 123 // Allow passing in no headers for cleaner code 124 if len(headers) == 0 { 125 return s, nil 126 } 127 // Sanity check that the headers can be applied 128 for i := 0; i < len(headers)-1; i++ { 129 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 130 return nil, errOutOfRangeChain 131 } 132 } 133 if headers[0].Number.Uint64() != s.Number+1 { 134 return nil, errOutOfRangeChain 135 } 136 // Iterate through the headers and create a new snapshot 137 snap := s.copy() 138 139 for _, header := range headers { 140 // Remove any votes on checkpoint blocks 141 number := header.Number.Uint64() 142 143 // Delete the oldest signer from the recent list to allow it signing again 144 if number >= s.config.Sprint && number-s.config.Sprint >= 0 { 145 delete(snap.Recents, number-s.config.Sprint) 146 } 147 148 // Resolve the authorization key and check against signers 149 signer, err := ecrecover(header, s.sigcache) 150 if err != nil { 151 return nil, err 152 } 153 154 // check if signer is in validator set 155 if !snap.ValidatorSet.HasAddress(signer.Bytes()) { 156 return nil, errUnauthorizedSigner 157 } 158 159 // 160 // Check validator 161 // 162 163 validators := snap.ValidatorSet.Validators 164 // proposer will be the last signer if block is not epoch block 165 proposer := snap.ValidatorSet.GetProposer().Address 166 proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer) 167 signerIndex, _ := snap.ValidatorSet.GetByAddress(signer) 168 limit := len(validators)/2 + 1 169 170 // temp index 171 tempIndex := signerIndex 172 if proposerIndex != tempIndex && limit > 0 { 173 if tempIndex < proposerIndex { 174 tempIndex = tempIndex + len(validators) 175 } 176 177 if tempIndex-proposerIndex > limit { 178 log.Info("Invalid signer: error while applying headers", "proposerIndex", validators[proposerIndex].Address.Hex(), "signerIndex", validators[signerIndex].Address.Hex()) 179 return nil, errRecentlySigned 180 } 181 } 182 183 // add recents 184 snap.Recents[number] = signer 185 186 // change validator set and change proposer 187 if number > 0 && (number+1)%s.config.Sprint == 0 { 188 validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal] 189 190 // get validators from headers and use that for new validator set 191 newVals, _ := ParseValidators(validatorBytes) 192 v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals) 193 v.IncrementProposerPriority(1) 194 snap.ValidatorSet = v 195 } 196 } 197 snap.Number += uint64(len(headers)) 198 snap.Hash = headers[len(headers)-1].Hash() 199 200 return snap, nil 201 } 202 203 // signers retrieves the list of authorized signers in ascending order. 204 func (s *Snapshot) signers() []common.Address { 205 sigs := make([]common.Address, 0, len(s.ValidatorSet.Validators)) 206 for _, sig := range s.ValidatorSet.Validators { 207 sigs = append(sigs, sig.Address) 208 } 209 return sigs 210 } 211 212 // inturn returns if a signer at a given block height is in-turn or not. 213 func (s *Snapshot) inturn(number uint64, signer common.Address, epoch uint64) uint64 { 214 // if signer is empty 215 if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 { 216 return 1 217 } 218 219 validators := s.ValidatorSet.Validators 220 proposer := s.ValidatorSet.GetProposer().Address 221 totalValidators := len(validators) 222 223 proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer) 224 signerIndex, _ := s.ValidatorSet.GetByAddress(signer) 225 226 // temp index 227 tempIndex := signerIndex 228 if tempIndex < proposerIndex { 229 tempIndex = tempIndex + totalValidators 230 } 231 232 return uint64(totalValidators - (tempIndex - proposerIndex)) 233 }