github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/consensus/ethash/snapshot.go (about) 1 // Copyright 2018 Wanchain Foundation Ltd 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // The code is mostly inspired by POA of ethereum 18 19 package ethash 20 21 import ( 22 "container/list" 23 "encoding/json" 24 "errors" 25 26 "github.com/wanchain/go-wanchain/common" 27 "github.com/wanchain/go-wanchain/core/types" 28 "github.com/wanchain/go-wanchain/ethdb" 29 "strings" 30 "fmt" 31 ) 32 33 const ( 34 windowRatio = 2 // 35 ) 36 37 type Snapshot struct { 38 PermissionSigners map[common.Address]struct{} 39 40 Number uint64 41 Hash common.Hash 42 UsedSigners map[common.Address]struct{} 43 RecentSignersWindow *list.List 44 } 45 46 type plainSnapShot struct { 47 PermissionSigners map[common.Address]struct{} `json:"permissionSigners"` 48 49 Number uint64 `json:"number"` 50 Hash common.Hash `json:"hash"` 51 UsedSigners map[common.Address]struct{} `json:"usedSigners"` 52 RecentSignersWindow []common.Address `json:"recentSignersWindow"` 53 } 54 55 func newSnapshot(number uint64, hash common.Hash, signers []common.Address) *Snapshot { 56 snap := &Snapshot{ 57 PermissionSigners: make(map[common.Address]struct{}), 58 Number: number, 59 Hash: hash, 60 UsedSigners: make(map[common.Address]struct{}), 61 RecentSignersWindow: list.New(), 62 } 63 64 for _, s := range signers { 65 snap.PermissionSigners[s] = struct{}{} 66 } 67 68 return snap 69 } 70 71 func loadSnapShot(db ethdb.Database, hash common.Hash) (*Snapshot, error) { 72 blob, err := db.Get(append([]byte("ppow-"), hash[:]...)) 73 if err != nil { 74 return nil, err 75 } 76 77 plain := new(plainSnapShot) 78 if err := json.Unmarshal(blob, plain); err != nil { 79 return nil, err 80 } 81 82 snap := &Snapshot{ 83 PermissionSigners: plain.PermissionSigners, 84 Number: plain.Number, 85 Hash: plain.Hash, 86 UsedSigners: plain.UsedSigners, 87 RecentSignersWindow: list.New(), 88 } 89 90 for _, v := range plain.RecentSignersWindow { 91 snap.RecentSignersWindow.PushBack(v) 92 } 93 94 return snap, nil 95 } 96 97 func (s *Snapshot) store(db ethdb.Database) error { 98 plain := &plainSnapShot{ 99 PermissionSigners: s.PermissionSigners, 100 Number: s.Number, 101 Hash: s.Hash, 102 UsedSigners: s.UsedSigners, 103 RecentSignersWindow: make([]common.Address, 0), 104 } 105 106 for e := s.RecentSignersWindow.Front(); e != nil; e = e.Next() { 107 if _, ok := e.Value.(common.Address); ok { 108 plain.RecentSignersWindow = append(plain.RecentSignersWindow, e.Value.(common.Address)) 109 } 110 } 111 112 blob, err := json.Marshal(plain) 113 if err != nil { 114 return err 115 } 116 117 return db.Put(append([]byte("ppow-"), plain.Hash[:]...), blob) 118 } 119 120 func (s *Snapshot) copy() *Snapshot { 121 cpy := &Snapshot{ 122 PermissionSigners: s.PermissionSigners, 123 Number: s.Number, 124 Hash: s.Hash, 125 UsedSigners: make(map[common.Address]struct{}), 126 RecentSignersWindow: list.New(), 127 } 128 129 for signer := range s.UsedSigners { 130 cpy.UsedSigners[signer] = struct{}{} 131 } 132 cpy.RecentSignersWindow.PushBackList(s.RecentSignersWindow) 133 return cpy 134 } 135 136 func (s *Snapshot) updateSignerStatus(signer common.Address, isExist bool) { 137 if isExist { 138 //if signer already presence 139 if (s.RecentSignersWindow.Len()) > 0 { 140 s.RecentSignersWindow.PushFront(signer) 141 s.RecentSignersWindow.Remove(s.RecentSignersWindow.Back()) 142 } 143 } else { 144 // This is the first time the signer appear 145 s.UsedSigners[signer] = struct{}{} 146 preWindowLen := s.RecentSignersWindow.Len() 147 newWindowLen := (len(s.UsedSigners) - 1) / windowRatio 148 if newWindowLen > preWindowLen { 149 s.RecentSignersWindow.PushFront(signer) 150 } else { 151 //windowLen unchanged 152 if newWindowLen > 0 { 153 s.RecentSignersWindow.PushFront(signer) 154 s.RecentSignersWindow.Remove(s.RecentSignersWindow.Back()) 155 } 156 } 157 } 158 } 159 160 // apply creates a new authorization snapshot by applying the given headers to 161 // the original one. 162 // PermissionSigners is the full set of signers who can sign blocks 163 // UsedSigners is the set of signers who had sign blocks 164 // RecentSignersWindow is the set who can not sign next block 165 // len(RecentSignersWindow) = (len(UsedSigners)-1)/2 166 // so when n > 2, hacker should got (n / 2 + 1) key to reorg chain? 167 func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { 168 if len(headers) == 0 { 169 return s, nil 170 } 171 // Sanity check that the headers can be applied 172 for i := 0; i < len(headers)-1; i++ { 173 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 174 return nil, errors.New("invalid applied headers") 175 } 176 } 177 if headers[0].Number.Uint64() != s.Number+1 { 178 return nil, errors.New("invalid applied header to snapshot") 179 } 180 181 snap := s.copy() 182 183 for _, header := range headers { 184 signer, err := ecrecover(header) 185 if err != nil || 0 != strings.Compare(signer.String(), header.Coinbase.String()) { 186 return nil, err 187 } 188 189 err = snap.isLegal4Sign(signer) 190 if err != nil { 191 return nil, err 192 } 193 194 _, ok := snap.UsedSigners[signer] 195 snap.updateSignerStatus(signer, ok) 196 } 197 198 snap.Hash = headers[len(headers)-1].Hash() 199 snap.Number = headers[len(headers)-1].Number.Uint64() 200 201 return snap, nil 202 } 203 204 func (s *Snapshot) isLegal4Sign(signer common.Address) error { 205 if _, ok := s.PermissionSigners[signer]; !ok { 206 fmt.Println(common.ToHex(signer[:])) 207 return errUnauthorized 208 } 209 210 for e := s.RecentSignersWindow.Front(); e != nil; e = e.Next() { 211 if _, ok := e.Value.(common.Address); ok { 212 wSigner := e.Value.(common.Address) 213 if signer == wSigner { 214 return errAuthorTooOften 215 } 216 } 217 } 218 return nil 219 }