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