github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/consensus/dpos/epoch_context_test.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 package dpos 10 11 import ( 12 "math/big" 13 "strconv" 14 "strings" 15 "testing" 16 17 "github.com/ethereum/go-ethereum/common" 18 "github.com/ethereum/go-ethereum/core/state" 19 "github.com/ethereum/go-ethereum/core/types" 20 "github.com/ethereum/go-ethereum/ethdb" 21 "github.com/ethereum/go-ethereum/trie" 22 23 "github.com/stretchr/testify/assert" 24 ) 25 26 func TestEpochContextCountVotes(t *testing.T) { 27 voteMap := map[common.Address][]common.Address{ 28 common.HexToAddress("0x44d1ce0b7cb3588bca96151fe1bc05af38f91b6e"): { 29 common.HexToAddress("0xb040353ec0f2c113d5639444f7253681aecda1f8"), 30 }, 31 common.HexToAddress("0xa60a3886b552ff9992cfcd208ec1152079e046c2"): { 32 common.HexToAddress("0x14432e15f21237013017fa6ee90fc99433dec82c"), 33 common.HexToAddress("0x9f30d0e5c9c88cade54cd1adecf6bc2c7e0e5af6"), 34 }, 35 common.HexToAddress("0x4e080e49f62694554871e669aeb4ebe17c4a9670"): { 36 common.HexToAddress("0xd83b44a3719720ec54cdb9f54c0202de68f1ebcb"), 37 common.HexToAddress("0x56cc452e450551b7b9cffe25084a069e8c1e9441"), 38 common.HexToAddress("0xbcfcb3fa8250be4f2bf2b1e70e1da500c668377b"), 39 }, 40 common.HexToAddress("0x9d9667c71bb09d6ca7c3ed12bfe5e7be24e2ffe1"): {}, 41 } 42 balance := int64(5) 43 db := ethdb.NewMemDatabase() 44 stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db)) 45 trieDB := trie.NewDatabase(db) 46 dposContext, err := types.NewDposContext(trieDB) 47 assert.Nil(t, err) 48 49 epochContext := &EpochContext{ 50 DposContext: dposContext, 51 statedb: stateDB, 52 } 53 _, err = epochContext.countVotes() 54 assert.NotNil(t, err) 55 56 for candidate, electors := range voteMap { 57 assert.Nil(t, dposContext.BecomeCandidate(candidate)) 58 for _, elector := range electors { 59 stateDB.SetBalance(elector, big.NewInt(balance)) 60 assert.Nil(t, dposContext.Delegate(elector, candidate)) 61 } 62 } 63 result, err := epochContext.countVotes() 64 assert.Nil(t, err) 65 assert.Equal(t, len(voteMap), len(result)) 66 for candidate, electors := range voteMap { 67 voteCount, ok := result[candidate] 68 assert.True(t, ok) 69 assert.Equal(t, balance*int64(len(electors)), voteCount.Int64()) 70 } 71 } 72 73 func TestLookupValidator(t *testing.T) { 74 db := ethdb.NewMemDatabase() 75 trieDB := trie.NewDatabase(db) 76 dposCtx, _ := types.NewDposContext(trieDB) 77 mockEpochContext := &EpochContext{ 78 DposContext: dposCtx, 79 } 80 validators := []common.Address{ 81 common.StringToAddress("addr1"), 82 common.StringToAddress("addr2"), 83 common.StringToAddress("addr3"), 84 } 85 mockEpochContext.DposContext.SetValidators(validators) 86 for i, expected := range validators { 87 got, _ := mockEpochContext.lookupValidator(int64(i) * blockInterval) 88 if got != expected { 89 t.Errorf("Failed to test lookup validator, %s was expected but got %s", expected.Str(), got.Str()) 90 } 91 } 92 blockInterval := 10 93 _, err := mockEpochContext.lookupValidator(blockInterval - 1) 94 if err != ErrInvalidMintBlockTime { 95 t.Errorf("Failed to test lookup validator. err '%v' was expected but got '%v'", ErrInvalidMintBlockTime, err) 96 } 97 } 98 99 func TestEpochContextKickoutValidator(t *testing.T) { 100 db := ethdb.NewMemDatabase() 101 stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db)) 102 trieDB := trie.NewDatabase(db) 103 dposContext, err := types.NewDposContext(trieDB) 104 assert.Nil(t, err) 105 epochContext := &EpochContext{ 106 TimeStamp: epochInterval, 107 DposContext: dposContext, 108 statedb: stateDB, 109 } 110 atLeastMintCnt := epochInterval / blockInterval / maxValidatorSize / 2 111 testEpoch := int64(1) 112 113 //没有验证器可以被踢出,因为所有验证器至少能制造足够的块。 114 validators := []common.Address{} 115 for i := 0; i < maxValidatorSize; i++ { 116 validator := common.StringToAddress("addr" + strconv.Itoa(i)) 117 validators = append(validators, validator) 118 assert.Nil(t, dposContext.BecomeCandidate(validator)) 119 setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt) 120 } 121 assert.Nil(t, dposContext.SetValidators(validators)) 122 assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr"))) 123 assert.Nil(t, epochContext.kickoutValidator(testEpoch)) 124 candidateMap := getCandidates(dposContext.CandidateTrie()) 125 assert.Equal(t, maxValidatorSize +1, len(candidateMap)) 126 127 //至少有一个最安全的候选人将保留 128 trieDB = trie.NewDatabase(db) 129 dposContext, err = types.NewDposContext(trieDB) 130 assert.Nil(t, err) 131 epochContext = &EpochContext{ 132 TimeStamp: epochInterval, 133 DposContext: dposContext, 134 statedb: stateDB, 135 } 136 validators = []common.Address{} 137 for i := 0; i < maxValidatorSize; i++ { 138 validator := common.StringToAddress("addr" + strconv.Itoa(i)) 139 validators = append(validators, validator) 140 assert.Nil(t, dposContext.BecomeCandidate(validator)) 141 setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-int64(i)-1) 142 } 143 assert.Nil(t, dposContext.SetValidators(validators)) 144 assert.Nil(t, epochContext.kickoutValidator(testEpoch)) 145 candidateMap = getCandidates(dposContext.CandidateTrie()) 146 assert.Equal(t, safeSize, len(candidateMap)) 147 for i := maxValidatorSize - 1; i >= safeSize; i-- { 148 assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(i))]) 149 } 150 151 //所有验证器都将被取消,因为所有验证器至少没有创建足够的块。 152 trieDB = trie.NewDatabase(db) 153 dposContext, err = types.NewDposContext(trieDB) 154 assert.Nil(t, err) 155 epochContext = &EpochContext{ 156 TimeStamp: epochInterval, 157 DposContext: dposContext, 158 statedb: stateDB, 159 } 160 validators = []common.Address{} 161 for i := 0; i < maxValidatorSize; i++ { 162 validator := common.StringToAddress("addr" + strconv.Itoa(i)) 163 validators = append(validators, validator) 164 assert.Nil(t, dposContext.BecomeCandidate(validator)) 165 setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1) 166 } 167 for i := maxValidatorSize; i < maxValidatorSize *2; i++ { 168 candidate := common.StringToAddress("addr" + strconv.Itoa(i)) 169 assert.Nil(t, dposContext.BecomeCandidate(candidate)) 170 } 171 assert.Nil(t, dposContext.SetValidators(validators)) 172 assert.Nil(t, epochContext.kickoutValidator(testEpoch)) 173 candidateMap = getCandidates(dposContext.CandidateTrie()) 174 assert.Equal(t, maxValidatorSize, len(candidateMap)) 175 176 //只有一个验证器铸币计数不够 177 trieDB = trie.NewDatabase(db) 178 dposContext, err = types.NewDposContext(trieDB) 179 assert.Nil(t, err) 180 epochContext = &EpochContext{ 181 TimeStamp: epochInterval, 182 DposContext: dposContext, 183 statedb: stateDB, 184 } 185 validators = []common.Address{} 186 for i := 0; i < maxValidatorSize; i++ { 187 validator := common.StringToAddress("addr" + strconv.Itoa(i)) 188 validators = append(validators, validator) 189 assert.Nil(t, dposContext.BecomeCandidate(validator)) 190 if i == 0 { 191 setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1) 192 } else { 193 setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt) 194 } 195 } 196 assert.Nil(t, dposContext.BecomeCandidate(common.StringToAddress("addr"))) 197 assert.Nil(t, dposContext.SetValidators(validators)) 198 assert.Nil(t, epochContext.kickoutValidator(testEpoch)) 199 candidateMap = getCandidates(dposContext.CandidateTrie()) 200 assert.Equal(t, maxValidatorSize, len(candidateMap)) 201 assert.False(t, candidateMap[common.StringToAddress("addr"+strconv.Itoa(0))]) 202 203 //epochtime不完整,所有验证器都至少创建足够的块 204 trieDB = trie.NewDatabase(db) 205 dposContext, err = types.NewDposContext(trieDB) 206 assert.Nil(t, err) 207 epochContext = &EpochContext{ 208 TimeStamp: epochInterval / 2, 209 DposContext: dposContext, 210 statedb: stateDB, 211 } 212 validators = []common.Address{} 213 for i := 0; i < maxValidatorSize; i++ { 214 validator := common.StringToAddress("addr" + strconv.Itoa(i)) 215 validators = append(validators, validator) 216 assert.Nil(t, dposContext.BecomeCandidate(validator)) 217 setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2) 218 } 219 for i := maxValidatorSize; i < maxValidatorSize *2; i++ { 220 candidate := common.StringToAddress("addr" + strconv.Itoa(i)) 221 assert.Nil(t, dposContext.BecomeCandidate(candidate)) 222 } 223 assert.Nil(t, dposContext.SetValidators(validators)) 224 assert.Nil(t, epochContext.kickoutValidator(testEpoch)) 225 candidateMap = getCandidates(dposContext.CandidateTrie()) 226 assert.Equal(t, maxValidatorSize *2, len(candidateMap)) 227 228 //epochtime不完整,所有验证器至少没有创建足够的块 229 trieDB = trie.NewDatabase(db) 230 dposContext, err = types.NewDposContext(trieDB) 231 assert.Nil(t, err) 232 epochContext = &EpochContext{ 233 TimeStamp: epochInterval / 2, 234 DposContext: dposContext, 235 statedb: stateDB, 236 } 237 validators = []common.Address{} 238 for i := 0; i < maxValidatorSize; i++ { 239 validator := common.StringToAddress("addr" + strconv.Itoa(i)) 240 validators = append(validators, validator) 241 assert.Nil(t, dposContext.BecomeCandidate(validator)) 242 setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt/2-1) 243 } 244 for i := maxValidatorSize; i < maxValidatorSize *2; i++ { 245 candidate := common.StringToAddress("addr" + strconv.Itoa(i)) 246 assert.Nil(t, dposContext.BecomeCandidate(candidate)) 247 } 248 assert.Nil(t, dposContext.SetValidators(validators)) 249 assert.Nil(t, epochContext.kickoutValidator(testEpoch)) 250 candidateMap = getCandidates(dposContext.CandidateTrie()) 251 assert.Equal(t, maxValidatorSize, len(candidateMap)) 252 253 trieDB = trie.NewDatabase(db) 254 dposContext, err = types.NewDposContext(trieDB) 255 assert.Nil(t, err) 256 epochContext = &EpochContext{ 257 TimeStamp: epochInterval / 2, 258 DposContext: dposContext, 259 statedb: stateDB, 260 } 261 assert.NotNil(t, epochContext.kickoutValidator(testEpoch)) 262 dposContext.SetValidators([]common.Address{}) 263 assert.NotNil(t, epochContext.kickoutValidator(testEpoch)) 264 } 265 266 func setTestMintCnt(dposContext *types.DposContext, epoch int64, validator common.Address, count int64) { 267 for i := int64(0); i < count; i++ { 268 updateMintCnt(epoch*epochInterval, epoch*epochInterval+blockInterval, validator, dposContext) 269 } 270 } 271 272 func getCandidates(candidateTrie *trie.Trie) map[common.Address]bool { 273 candidateMap := map[common.Address]bool{} 274 iter := trie.NewIterator(candidateTrie.NodeIterator(nil)) 275 for iter.Next() { 276 candidateMap[common.BytesToAddress(iter.Value)] = true 277 } 278 return candidateMap 279 } 280 281 func TestEpochContextTryElect(t *testing.T) { 282 db := ethdb.NewMemDatabase() 283 stateDB, _ := state.New(common.Hash{}, state.NewDatabase(db)) 284 trieDB := trie.NewDatabase(db) 285 dposContext, err := types.NewDposContext(trieDB) 286 assert.Nil(t, err) 287 epochContext := &EpochContext{ 288 TimeStamp: epochInterval, 289 DposContext: dposContext, 290 statedb: stateDB, 291 } 292 atLeastMintCnt := epochInterval / blockInterval / maxValidatorSize / 2 293 testEpoch := int64(1) 294 validators := []common.Address{} 295 for i := 0; i < maxValidatorSize; i++ { 296 validator := common.StringToAddress("addr" + strconv.Itoa(i)) 297 validators = append(validators, validator) 298 assert.Nil(t, dposContext.BecomeCandidate(validator)) 299 assert.Nil(t, dposContext.Delegate(validator, validator)) 300 stateDB.SetBalance(validator, big.NewInt(1)) 301 setTestMintCnt(dposContext, testEpoch, validator, atLeastMintCnt-1) 302 } 303 dposContext.BecomeCandidate(common.StringToAddress("more")) 304 assert.Nil(t, dposContext.SetValidators(validators)) 305 306 //genesisepoch==parentepoch不开始 307 genesis := &types.Header{ 308 Time: big.NewInt(0), 309 } 310 parent := &types.Header{ 311 Time: big.NewInt(epochInterval - blockInterval), 312 } 313 oldHash := dposContext.EpochTrie().Hash() 314 assert.Nil(t, epochContext.tryElect(genesis, parent)) 315 result, err := dposContext.GetValidators() 316 assert.Nil(t, err) 317 assert.Equal(t, maxValidatorSize, len(result)) 318 for _, validator := range result { 319 assert.True(t, strings.Contains(validator.Str(), "addr")) 320 } 321 assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash()) 322 323 //基因时代!=parentepoch和have none mintcnt不退出 324 genesis = &types.Header{ 325 Time: big.NewInt(-epochInterval), 326 } 327 parent = &types.Header{ 328 Difficulty: big.NewInt(1), 329 Time: big.NewInt(epochInterval - blockInterval), 330 } 331 epochContext.TimeStamp = epochInterval 332 oldHash = dposContext.EpochTrie().Hash() 333 assert.Nil(t, epochContext.tryElect(genesis, parent)) 334 result, err = dposContext.GetValidators() 335 assert.Nil(t, err) 336 assert.Equal(t, maxValidatorSize, len(result)) 337 for _, validator := range result { 338 assert.True(t, strings.Contains(validator.Str(), "addr")) 339 } 340 assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash()) 341 342 //基因时代!=ParentEpoch启动 343 genesis = &types.Header{ 344 Time: big.NewInt(0), 345 } 346 parent = &types.Header{ 347 Time: big.NewInt(epochInterval*2 - blockInterval), 348 } 349 epochContext.TimeStamp = epochInterval * 2 350 oldHash = dposContext.EpochTrie().Hash() 351 assert.Nil(t, epochContext.tryElect(genesis, parent)) 352 result, err = dposContext.GetValidators() 353 assert.Nil(t, err) 354 assert.Equal(t, safeSize, len(result)) 355 moreCnt := 0 356 for _, validator := range result { 357 if strings.Contains(validator.Str(), "more") { 358 moreCnt++ 359 } 360 } 361 assert.Equal(t, 1, moreCnt) 362 assert.NotEqual(t, oldHash, dposContext.EpochTrie().Hash()) 363 364 //parentepoch==currentpoch不选择 365 genesis = &types.Header{ 366 Time: big.NewInt(0), 367 } 368 parent = &types.Header{ 369 Time: big.NewInt(epochInterval), 370 } 371 epochContext.TimeStamp = epochInterval + blockInterval 372 oldHash = dposContext.EpochTrie().Hash() 373 assert.Nil(t, epochContext.tryElect(genesis, parent)) 374 result, err = dposContext.GetValidators() 375 assert.Nil(t, err) 376 assert.Equal(t, safeSize, len(result)) 377 assert.Equal(t, oldHash, dposContext.EpochTrie().Hash()) 378 }