github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/consensus/ethash/snapshot_test.go (about) 1 // Copyright 2018 Wanchain Foundation Ltd 2 3 package ethash 4 5 import ( 6 "crypto/ecdsa" 7 "math/big" 8 "math/rand" 9 "strings" 10 "testing" 11 12 "github.com/wanchain/go-wanchain/common" 13 "github.com/wanchain/go-wanchain/core/types" 14 "github.com/wanchain/go-wanchain/crypto" 15 "github.com/wanchain/go-wanchain/ethdb" 16 ) 17 18 type SignerInfo struct { 19 private *ecdsa.PrivateKey 20 addr common.Address 21 str string 22 index int 23 } 24 25 var ( 26 // assert never be lower than 6 27 totalSigner = 20 28 signerSet = make(map[string]*SignerInfo) 29 addrStrArray = make([]string, 0) 30 addrArray = make([]common.Address, 0) 31 indexAddrStrMap = make(map[int]string) 32 unAuthorizedSigner = common.Address{} 33 unAuthorizedPrivateKey *ecdsa.PrivateKey = nil 34 ) 35 36 func init() { 37 // generate 38 for i := 0; i < totalSigner; i++ { 39 private, _ := crypto.GenerateKey() 40 addr := crypto.PubkeyToAddress(private.PublicKey) 41 str := addr.String() 42 signerSet[str] = &SignerInfo{private: private, addr: addr, str: str, index: i} 43 addrStrArray = append(addrStrArray, str) 44 addrArray = append(addrArray, addr) 45 indexAddrStrMap[i] = str 46 } 47 unAuthorizedPrivateKey, _ = crypto.GenerateKey() 48 unAuthorizedSigner.Set(crypto.PubkeyToAddress(unAuthorizedPrivateKey.PublicKey)) 49 } 50 51 //store and retrieve permission pow 52 func TestStoreAndLoadEmptySnapshot(t *testing.T) { 53 //create a initial snapshot with only one permission signer 54 addr := addrStrArray[0] 55 genesisAddr := signerSet[addr].addr 56 hash := crypto.Keccak256Hash([]byte{0}) 57 s := newSnapshot(0, hash, []common.Address{genesisAddr}) 58 59 db, _ := ethdb.NewMemDatabase() 60 s.store(db) 61 62 sload, _ := loadSnapShot(db, hash) 63 if len(sload.PermissionSigners) != 1 || sload.Number != 0 || 64 len(sload.UsedSigners) != 0 || sload.RecentSignersWindow.Len() != 0 { 65 t.Error("load snapshot failed") 66 } 67 68 if _, ok := sload.PermissionSigners[genesisAddr]; !ok { 69 t.Error("load snapshot failed") 70 } 71 } 72 73 //store and retrieve permission pow 74 func TestStoreAndLoadRunningSnapshot(t *testing.T) { 75 hash := crypto.Keccak256Hash([]byte{0}) 76 blockNumber := uint64(88) 77 s := newSnapshot(blockNumber, hash, addrArray) 78 79 usedCount := totalSigner / 2 80 for i := 0; i < usedCount; i++ { 81 s.UsedSigners[addrArray[i]] = struct{}{} 82 } 83 84 windowLen := (usedCount - 1) / 2 85 for i := windowLen - 1; i >= 0; i-- { 86 s.RecentSignersWindow.PushFront(addrArray[i]) 87 } 88 89 db, _ := ethdb.NewMemDatabase() 90 s.store(db) 91 92 sload, _ := loadSnapShot(db, hash) 93 if len(sload.PermissionSigners) != totalSigner || sload.Number != blockNumber || 94 len(sload.UsedSigners) != usedCount || sload.RecentSignersWindow.Len() != windowLen { 95 t.Error("load snapshot failed") 96 } 97 98 for i := 0; i < usedCount; i++ { 99 if _, ok := sload.PermissionSigners[addrArray[i]]; !ok { 100 t.Error("load snapshot failed") 101 } 102 } 103 104 i := 0 105 for e := s.RecentSignersWindow.Front(); e != nil; e = e.Next() { 106 addr := e.Value.(common.Address) 107 if strings.Compare(addr.String(), addrStrArray[i]) != 0 { 108 t.Error("error in recent window store or retrieve") 109 } 110 i++ 111 } 112 if i != windowLen { 113 t.Error("window length is not right") 114 } 115 } 116 117 func sign(header *types.Header, signer common.Address) { 118 si := signerSet[signer.String()] 119 sig, _ := crypto.Sign(sigHash(header).Bytes(), si.private) 120 copy(header.Extra[len(header.Extra)-65:], sig) 121 } 122 123 // indexes indicated use which signer to sign header 124 func prepareHeaders(indexes []int, blockNumbers []int) []*types.Header { 125 headers := make([]*types.Header, 0) 126 for i, n := range indexes { 127 signer := addrArray[n] 128 h := &types.Header{ 129 Coinbase: signer, 130 Time: big.NewInt(int64(blockNumbers[i]) * int64(1000)), 131 Number: big.NewInt(int64(blockNumbers[i])), 132 Extra: make([]byte, extraSeal+extraVanity), 133 } 134 sign(h, signer) 135 headers = append(headers, h) 136 } 137 return headers 138 } 139 140 func prepareUnAuthorizedSignerHeader(blockNumber int) []*types.Header { 141 headers := make([]*types.Header, 0) 142 h := &types.Header{ 143 Coinbase: unAuthorizedSigner, 144 Time: big.NewInt(int64(blockNumber) * int64(1000)), 145 Number: big.NewInt(int64(blockNumber)), 146 Extra: make([]byte, extraSeal+extraVanity), 147 } 148 sig, _ := crypto.Sign(sigHash(h).Bytes(), unAuthorizedPrivateKey) 149 copy(h.Extra[len(h.Extra)-65:], sig) 150 headers = append(headers, h) 151 return headers 152 } 153 154 func TestPPOWApplyingFixedCorrectHeaders(t *testing.T) { 155 hash := crypto.Keccak256Hash([]byte{0}) 156 blockNumber := 0 157 s := newSnapshot(uint64(blockNumber), hash, addrArray) 158 blockNumber++ 159 160 usingSigners := totalSigner - 3 161 signerIndexes := make([]int, 0) 162 blockNumbers := make([]int, 0) 163 expectWindowLen := (usingSigners - 1) / 2 164 for i := 0; i < usingSigners; i++ { 165 signerIndexes = append(signerIndexes, i) 166 blockNumbers = append(blockNumbers, blockNumber) 167 blockNumber++ 168 } 169 for i := 0; i < expectWindowLen; i++ { 170 signerIndexes = append(signerIndexes, i) 171 blockNumbers = append(blockNumbers, blockNumber) 172 blockNumber++ 173 } 174 headers := prepareHeaders(signerIndexes, blockNumbers) 175 _, err := s.apply(headers) 176 if err != nil { 177 t.Error("apply shouldn't be failed ") 178 } 179 180 for i := 0; i < usingSigners; i++ { 181 if _, ok := s.PermissionSigners[addrArray[i]]; !ok { 182 t.Error("used signer didn't record") 183 } 184 } 185 186 expectedIndex := expectWindowLen - 1 187 for e := s.RecentSignersWindow.Front(); e != nil; e = e.Next() { 188 addr := e.Value.(common.Address) 189 if strings.Compare(addr.String(), addrStrArray[expectedIndex]) != 0 { 190 t.Error("error in recent window store or retrieve") 191 } 192 expectedIndex-- 193 } 194 } 195 196 func TestPPOWApplyingErrBlockNumberHeaders(t *testing.T) { 197 hash := crypto.Keccak256Hash([]byte{0}) 198 blockNumber := 0 199 s := newSnapshot(uint64(blockNumber), hash, addrArray) 200 blockNumber++ 201 202 //invalid block headers number order 203 invalidNumberHeaders := prepareHeaders([]int{0, 1}, []int{blockNumber + 1, blockNumber}) 204 _, err := s.apply(invalidNumberHeaders) 205 if err == nil { 206 t.Error("apply error invalid order block number") 207 } 208 } 209 210 func TestPPOWApplyingUnAuthorizedHeader(t *testing.T) { 211 hash := crypto.Keccak256Hash([]byte{0}) 212 blockNumber := 0 213 s := newSnapshot(uint64(blockNumber), hash, addrArray) 214 blockNumber++ 215 216 invalidNumberHeaders := prepareUnAuthorizedSignerHeader(blockNumber) 217 _, err := s.apply(invalidNumberHeaders) 218 if err == nil { 219 t.Error("apply error invalid order block number") 220 } 221 } 222 223 func TestPPOWApplyingNotContinueNumberHeaders(t *testing.T) { 224 hash := crypto.Keccak256Hash([]byte{0}) 225 blockNumber := 8 226 s := newSnapshot(uint64(blockNumber), hash, addrArray) 227 228 emptyHeaders := prepareHeaders([]int{}, []int{}) 229 _, err := s.apply(emptyHeaders) 230 if err != nil { 231 t.Error("process empty header list failed") 232 } 233 //invalid block headers number order 234 invalidNumberHeaders := prepareHeaders([]int{0}, []int{blockNumber}) 235 _, err = s.apply(invalidNumberHeaders) 236 if err == nil { 237 t.Error("apply error invalid order block number") 238 } 239 invalidNumberHeaders = prepareHeaders([]int{0}, []int{blockNumber - 1}) 240 _, err = s.apply(invalidNumberHeaders) 241 if err == nil { 242 t.Error("apply error invalid order block number") 243 } 244 invalidNumberHeaders = prepareHeaders([]int{0}, []int{blockNumber + 2}) 245 _, err = s.apply(invalidNumberHeaders) 246 if err == nil { 247 t.Error("apply error invalid order block number") 248 } 249 } 250 251 //if have error, then 252 func internalApply(snap *Snapshot, snapNumber uint64, headers []*types.Header, state *internalState) (uint64, *internalState) { 253 backupState := state.copy() 254 if len(headers) == 0 { 255 return snapNumber, backupState 256 } 257 258 for i := 0; i < len(headers)-1; i++ { 259 if headers[i+1].Number.Uint64() != headers[i].Number.Uint64()+1 { 260 return snapNumber, backupState 261 } 262 } 263 264 if headers[0].Number.Uint64() != snapNumber+1 { 265 return snapNumber, backupState 266 } 267 268 for _, header := range headers { 269 signer, err := ecrecover(header) 270 if err != nil || 0 != strings.Compare(signer.String(), header.Coinbase.String()) { 271 return snapNumber, backupState 272 } 273 274 if _, ok := snap.PermissionSigners[signer]; !ok { 275 return snapNumber, backupState 276 } 277 278 for _, wSigner := range state.testWindow { 279 if signer == wSigner { 280 return snapNumber, backupState 281 } 282 } 283 284 _, ok := state.testUsedSigners[signer] 285 internalUpdateWindow(state, signer, ok) 286 } 287 return headers[len(headers)-1].Number.Uint64(), state 288 } 289 290 func internalUpdateWindow(state *internalState, signer common.Address, isExist bool) { 291 if isExist { 292 //if signer already presence 293 if (len(state.testWindow)) > 0 { 294 backup := make([]common.Address, 0) 295 backup = append(backup, signer) 296 backup = append(backup, state.testWindow...) 297 state.testWindow = make([]common.Address, len(backup)-1) 298 copy(state.testWindow, backup[:len(backup)-1]) 299 } 300 } else { 301 // This is the first time the signer appear 302 state.testUsedSigners[signer] = struct{}{} 303 preWindowLen := len(state.testWindow) 304 newWindowLen := (len(state.testUsedSigners) - 1) / windowRatio 305 306 if newWindowLen > preWindowLen { 307 backup := make([]common.Address, 0) 308 backup = append(backup, signer) 309 backup = append(backup, state.testWindow...) 310 state.testWindow = make([]common.Address, len(backup)) 311 copy(state.testWindow, backup) 312 } else { 313 //windowLen unchanged 314 if newWindowLen > 0 { 315 backup := make([]common.Address, 0) 316 backup = append(backup, signer) 317 backup = append(backup, state.testWindow...) 318 state.testWindow = make([]common.Address, len(backup)-1) 319 copy(state.testWindow, backup[:len(backup)-1]) 320 } 321 } 322 } 323 } 324 325 type internalState struct { 326 testUsedSigners map[common.Address]struct{} 327 testWindow []common.Address 328 } 329 330 func (self *internalState) copy() *internalState { 331 cpy := &internalState{ 332 testUsedSigners: make(map[common.Address]struct{}), 333 testWindow: make([]common.Address, 0), 334 } 335 336 for k := range self.testUsedSigners { 337 cpy.testUsedSigners[k] = struct{}{} 338 } 339 340 for _, e := range self.testWindow { 341 cpy.testWindow = append(cpy.testWindow, e) 342 } 343 return cpy 344 } 345 346 // generate x times random headers to apply 347 func TestPPOWApplyingRandom(t *testing.T) { 348 tests := []struct { 349 headersLen int 350 loopTimes int 351 }{ 352 { 353 headersLen: 1, 354 loopTimes: 100, 355 }, 356 { 357 headersLen: 2, 358 loopTimes: 80, 359 }, 360 { 361 headersLen: 3, 362 loopTimes: 60, 363 }, 364 { 365 headersLen: 5, 366 loopTimes: 50, 367 }, 368 } 369 for _, loopInfo := range tests { 370 loops := totalSigner * loopInfo.loopTimes 371 hash := crypto.Keccak256Hash([]byte{0}) 372 blockNumber := 0 373 s := newSnapshot(uint64(blockNumber), hash, addrArray) 374 blockNumber++ 375 376 usingSigners := totalSigner - 5 377 378 state := &internalState{ 379 testUsedSigners: make(map[common.Address]struct{}), 380 testWindow: make([]common.Address, 0), 381 } 382 383 for ; loops > 0; loops-- { 384 number := s.Number + 1 385 indexes := make([]int, 0) 386 numbers := make([]int, 0) 387 for ri := 0; ri < loopInfo.headersLen; ri++ { 388 selectNumber := rand.Intn(usingSigners) 389 indexes = append(indexes, selectNumber) 390 numbers = append(numbers, int(number)) 391 number++ 392 } 393 headers := prepareHeaders(indexes, numbers) 394 reservedNumber := s.Number 395 ns, err := s.apply(headers) 396 if err == nil { 397 s = ns 398 } 399 var afterApplyNum uint64 400 afterApplyNum, state = internalApply(s, reservedNumber, headers, state) 401 if afterApplyNum != s.Number { 402 t.Errorf("invalid status of snapshot :snapshot num: %d compared num: %d\n", int(s.Number), int(afterApplyNum)) 403 } 404 } 405 //compare used signers and window equal 406 if len(state.testUsedSigners) != len(s.UsedSigners) { 407 t.Error("usedSigners length incorrect") 408 } 409 410 for signer := range state.testUsedSigners { 411 if _, ok := s.UsedSigners[signer]; !ok { 412 t.Error("used signers element invalid") 413 } 414 } 415 416 if s.RecentSignersWindow.Len() != len(state.testWindow) { 417 t.Error("recent signer window len incorrect") 418 } 419 420 windowIndex := 0 421 for e := s.RecentSignersWindow.Front(); e != nil; e = e.Next() { 422 addr := e.Value.(common.Address) 423 if strings.Compare(addr.String(), state.testWindow[windowIndex].String()) != 0 { 424 t.Error("error in recent window signer") 425 } 426 windowIndex++ 427 } 428 } 429 } 430 431 func TestIsSignerLegal(t *testing.T) { 432 hash := crypto.Keccak256Hash([]byte{0}) 433 blockNumber := 0 434 s := newSnapshot(uint64(blockNumber), hash, addrArray) 435 blockNumber++ 436 437 usingSigners := totalSigner - 3 438 signerIndexes := make([]int, 0) 439 blockNumbers := make([]int, 0) 440 for i := 0; i < usingSigners; i++ { 441 signerIndexes = append(signerIndexes, i) 442 blockNumbers = append(blockNumbers, blockNumber) 443 blockNumber++ 444 } 445 headers := prepareHeaders(signerIndexes, blockNumbers) 446 s, _ = s.apply(headers) 447 448 if nil == s.isLegal4Sign(unAuthorizedSigner) { 449 t.Error("invalid process unauthorized signer") 450 } 451 452 if nil == s.isLegal4Sign(addrArray[usingSigners-1]) { 453 t.Error("invalid process in window signer") 454 } 455 456 if nil != s.isLegal4Sign(addrArray[usingSigners]) { 457 t.Error("invalid process valid signer") 458 } 459 }