github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/consensus/clique/snapshot.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:34</date> 10 //</624450074558074880> 11 12 13 package clique 14 15 import ( 16 "bytes" 17 "encoding/json" 18 "sort" 19 20 "github.com/ethereum/go-ethereum/common" 21 "github.com/ethereum/go-ethereum/core/types" 22 "github.com/ethereum/go-ethereum/ethdb" 23 "github.com/ethereum/go-ethereum/params" 24 lru "github.com/hashicorp/golang-lru" 25 ) 26 27 //投票代表授权签名人修改 28 //授权列表。 29 type Vote struct { 30 Signer common.Address `json:"signer"` //投票的授权签署人 31 Block uint64 `json:"block"` //投票所投的区号(过期旧票) 32 Address common.Address `json:"address"` //正在投票更改其授权的帐户 33 Authorize bool `json:"authorize"` //是否授权或取消对投票帐户的授权 34 } 35 36 //计票是一种简单的计票方式,用来保持当前的计票结果。投票赞成 37 //反对这项提议并不算在内,因为它等同于不投票。 38 type Tally struct { 39 Authorize bool `json:"authorize"` //投票是授权还是踢某人 40 Votes int `json:"votes"` //到目前为止想要通过提案的票数 41 } 42 43 //快照是在给定时间点上投票的授权状态。 44 type Snapshot struct { 45 config *params.CliqueConfig //微调行为的一致引擎参数 46 sigcache *lru.ARCCache //缓存最近的块签名以加快ecrecover 47 48 Number uint64 `json:"number"` //创建快照的块号 49 Hash common.Hash `json:"hash"` //创建快照的块哈希 50 Signers map[common.Address]struct{} `json:"signers"` //此时的授权签名人集合 51 Recents map[uint64]common.Address `json:"recents"` //垃圾邮件保护的最近签名者集 52 Votes []*Vote `json:"votes"` //按时间顺序投票的名单 53 Tally map[common.Address]Tally `json:"tally"` //当前投票计数以避免重新计算 54 } 55 56 //SignerAscending实现排序接口,以允许对地址列表进行排序 57 type signersAscending []common.Address 58 59 func (s signersAscending) Len() int { return len(s) } 60 func (s signersAscending) Less(i, j int) bool { return bytes.Compare(s[i][:], s[j][:]) < 0 } 61 func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 62 63 //NewSnapshot使用指定的启动参数创建新快照。这个 64 //方法不初始化最近的签名者集,因此仅当用于 65 //创世纪板块。 66 func newSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, signers []common.Address) *Snapshot { 67 snap := &Snapshot{ 68 config: config, 69 sigcache: sigcache, 70 Number: number, 71 Hash: hash, 72 Signers: make(map[common.Address]struct{}), 73 Recents: make(map[uint64]common.Address), 74 Tally: make(map[common.Address]Tally), 75 } 76 for _, signer := range signers { 77 snap.Signers[signer] = struct{}{} 78 } 79 return snap 80 } 81 82 //LoadSnapshot从数据库加载现有快照。 83 func loadSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) { 84 blob, err := db.Get(append([]byte("clique-"), hash[:]...)) 85 if err != nil { 86 return nil, err 87 } 88 snap := new(Snapshot) 89 if err := json.Unmarshal(blob, snap); err != nil { 90 return nil, err 91 } 92 snap.config = config 93 snap.sigcache = sigcache 94 95 return snap, nil 96 } 97 98 //存储将快照插入数据库。 99 func (s *Snapshot) store(db ethdb.Database) error { 100 blob, err := json.Marshal(s) 101 if err != nil { 102 return err 103 } 104 return db.Put(append([]byte("clique-"), s.Hash[:]...), blob) 105 } 106 107 //复制创建快照的深度副本,尽管不是单个投票。 108 func (s *Snapshot) copy() *Snapshot { 109 cpy := &Snapshot{ 110 config: s.config, 111 sigcache: s.sigcache, 112 Number: s.Number, 113 Hash: s.Hash, 114 Signers: make(map[common.Address]struct{}), 115 Recents: make(map[uint64]common.Address), 116 Votes: make([]*Vote, len(s.Votes)), 117 Tally: make(map[common.Address]Tally), 118 } 119 for signer := range s.Signers { 120 cpy.Signers[signer] = struct{}{} 121 } 122 for block, signer := range s.Recents { 123 cpy.Recents[block] = signer 124 } 125 for address, tally := range s.Tally { 126 cpy.Tally[address] = tally 127 } 128 copy(cpy.Votes, s.Votes) 129 130 return cpy 131 } 132 133 //validvote返回在 134 //给定快照上下文(例如,不要尝试添加已授权的签名者)。 135 func (s *Snapshot) validVote(address common.Address, authorize bool) bool { 136 _, signer := s.Signers[address] 137 return (signer && !authorize) || (!signer && authorize) 138 } 139 140 //Cast在计票中添加了新的选票。 141 func (s *Snapshot) cast(address common.Address, authorize bool) bool { 142 //确保投票有意义 143 if !s.validVote(address, authorize) { 144 return false 145 } 146 //将投票投到现有或新的计票中 147 if old, ok := s.Tally[address]; ok { 148 old.Votes++ 149 s.Tally[address] = old 150 } else { 151 s.Tally[address] = Tally{Authorize: authorize, Votes: 1} 152 } 153 return true 154 } 155 156 //uncast从计票中删除先前的投票。 157 func (s *Snapshot) uncast(address common.Address, authorize bool) bool { 158 //如果没有计票结果,那是悬而未决的投票,就投吧。 159 tally, ok := s.Tally[address] 160 if !ok { 161 return false 162 } 163 //确保我们只还原已计数的投票 164 if tally.Authorize != authorize { 165 return false 166 } 167 //否则恢复投票 168 if tally.Votes > 1 { 169 tally.Votes-- 170 s.Tally[address] = tally 171 } else { 172 delete(s.Tally, address) 173 } 174 return true 175 } 176 177 //应用通过将给定的头应用于创建新的授权快照 178 //原来的那个。 179 func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { 180 //不允许传入清除器代码的头 181 if len(headers) == 0 { 182 return s, nil 183 } 184 //健全性检查标题是否可以应用 185 for i := 0; i < len(headers)-1; i++ { 186 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 187 return nil, errInvalidVotingChain 188 } 189 } 190 if headers[0].Number.Uint64() != s.Number+1 { 191 return nil, errInvalidVotingChain 192 } 193 //遍历头并创建新快照 194 snap := s.copy() 195 196 for _, header := range headers { 197 //删除检查点块上的所有投票 198 number := header.Number.Uint64() 199 if number%s.config.Epoch == 0 { 200 snap.Votes = nil 201 snap.Tally = make(map[common.Address]Tally) 202 } 203 //从最近列表中删除最早的签名者,以允许其再次签名。 204 if limit := uint64(len(snap.Signers)/2 + 1); number >= limit { 205 delete(snap.Recents, number-limit) 206 } 207 //解析授权密钥并检查签名者 208 signer, err := ecrecover(header, s.sigcache) 209 if err != nil { 210 return nil, err 211 } 212 if _, ok := snap.Signers[signer]; !ok { 213 return nil, errUnauthorizedSigner 214 } 215 for _, recent := range snap.Recents { 216 if recent == signer { 217 return nil, errRecentlySigned 218 } 219 } 220 snap.Recents[number] = signer 221 222 //标题已授权,放弃签名者以前的任何投票 223 for i, vote := range snap.Votes { 224 if vote.Signer == signer && vote.Address == header.Coinbase { 225 //从缓存的计数中取消投票 226 snap.uncast(vote.Address, vote.Authorize) 227 228 //取消按时间顺序排列的投票 229 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 230 break //只允许一票 231 } 232 } 233 //统计签名者的新投票 234 var authorize bool 235 switch { 236 case bytes.Equal(header.Nonce[:], nonceAuthVote): 237 authorize = true 238 case bytes.Equal(header.Nonce[:], nonceDropVote): 239 authorize = false 240 default: 241 return nil, errInvalidVote 242 } 243 if snap.cast(header.Coinbase, authorize) { 244 snap.Votes = append(snap.Votes, &Vote{ 245 Signer: signer, 246 Block: number, 247 Address: header.Coinbase, 248 Authorize: authorize, 249 }) 250 } 251 //如果投票通过,则更新签名者列表 252 if tally := snap.Tally[header.Coinbase]; tally.Votes > len(snap.Signers)/2 { 253 if tally.Authorize { 254 snap.Signers[header.Coinbase] = struct{}{} 255 } else { 256 delete(snap.Signers, header.Coinbase) 257 258 //签名者列表收缩,删除所有剩余的最近缓存 259 if limit := uint64(len(snap.Signers)/2 + 1); number >= limit { 260 delete(snap.Recents, number-limit) 261 } 262 //放弃取消授权签名者所投的任何以前的票 263 for i := 0; i < len(snap.Votes); i++ { 264 if snap.Votes[i].Signer == header.Coinbase { 265 //从缓存的计数中取消投票 266 snap.uncast(snap.Votes[i].Address, snap.Votes[i].Authorize) 267 268 //取消按时间顺序排列的投票 269 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 270 271 i-- 272 } 273 } 274 } 275 //放弃对刚刚更改的帐户的任何以前的投票 276 for i := 0; i < len(snap.Votes); i++ { 277 if snap.Votes[i].Address == header.Coinbase { 278 snap.Votes = append(snap.Votes[:i], snap.Votes[i+1:]...) 279 i-- 280 } 281 } 282 delete(snap.Tally, header.Coinbase) 283 } 284 } 285 snap.Number += uint64(len(headers)) 286 snap.Hash = headers[len(headers)-1].Hash() 287 288 return snap, nil 289 } 290 291 //签名者按升序检索授权签名者列表。 292 func (s *Snapshot) signers() []common.Address { 293 sigs := make([]common.Address, 0, len(s.Signers)) 294 for sig := range s.Signers { 295 sigs = append(sigs, sig) 296 } 297 sort.Sort(signersAscending(sigs)) 298 return sigs 299 } 300 301 //如果给定块高度的签名者依次是或不是,则Inturn返回。 302 func (s *Snapshot) inturn(number uint64, signer common.Address) bool { 303 signers, offset := s.signers(), 0 304 for offset < len(signers) && signers[offset] != signer { 305 offset++ 306 } 307 return (number % uint64(len(signers))) == uint64(offset) 308 } 309