github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/core/chain_indexer_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 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package core 26 27 import ( 28 "context" 29 "fmt" 30 "math/big" 31 "math/rand" 32 "testing" 33 "time" 34 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/core/rawdb" 37 "github.com/ethereum/go-ethereum/core/types" 38 "github.com/ethereum/go-ethereum/ethdb" 39 ) 40 41 //使用随机参数运行多个测试。 42 func TestChainIndexerSingle(t *testing.T) { 43 for i := 0; i < 10; i++ { 44 testChainIndexer(t, 1) 45 } 46 } 47 48 //使用随机参数和不同数量的 49 //链后端。 50 func TestChainIndexerWithChildren(t *testing.T) { 51 for i := 2; i < 8; i++ { 52 testChainIndexer(t, i) 53 } 54 } 55 56 //TestChainIndexer使用单个链索引器或 57 //多个后端。节大小和所需的确认计数参数 58 //是随机的。 59 func testChainIndexer(t *testing.T, count int) { 60 db := ethdb.NewMemDatabase() 61 defer db.Close() 62 63 //创建索引器链并确保它们都报告为空 64 backends := make([]*testChainIndexBackend, count) 65 for i := 0; i < count; i++ { 66 var ( 67 sectionSize = uint64(rand.Intn(100) + 1) 68 confirmsReq = uint64(rand.Intn(10)) 69 ) 70 backends[i] = &testChainIndexBackend{t: t, processCh: make(chan uint64)} 71 backends[i].indexer = NewChainIndexer(db, ethdb.NewTable(db, string([]byte{byte(i)})), backends[i], sectionSize, confirmsReq, 0, fmt.Sprintf("indexer-%d", i)) 72 73 if sections, _, _ := backends[i].indexer.Sections(); sections != 0 { 74 t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, 0) 75 } 76 if i > 0 { 77 backends[i-1].indexer.AddChildIndexer(backends[i].indexer) 78 } 79 } 80 defer backends[0].indexer.Close() //父索引器关闭子级 81 //通知ping根索引器有关新头或REORG的信息,然后 82 //如果节可处理,则处理块 83 notify := func(headNum, failNum uint64, reorg bool) { 84 backends[0].indexer.newHead(headNum, reorg) 85 if reorg { 86 for _, backend := range backends { 87 headNum = backend.reorg(headNum) 88 backend.assertSections() 89 } 90 return 91 } 92 var cascade bool 93 for _, backend := range backends { 94 headNum, cascade = backend.assertBlocks(headNum, failNum) 95 if !cascade { 96 break 97 } 98 backend.assertSections() 99 } 100 } 101 //inject将新的随机规范头直接插入数据库 102 inject := func(number uint64) { 103 header := &types.Header{Number: big.NewInt(int64(number)), Extra: big.NewInt(rand.Int63()).Bytes()} 104 if number > 0 { 105 header.ParentHash = rawdb.ReadCanonicalHash(db, number-1) 106 } 107 rawdb.WriteHeader(db, header) 108 rawdb.WriteCanonicalHash(db, header.Hash(), number) 109 } 110 //使用已存在的链启动索引器 111 for i := uint64(0); i <= 100; i++ { 112 inject(i) 113 } 114 notify(100, 100, false) 115 116 //逐个添加新块 117 for i := uint64(101); i <= 1000; i++ { 118 inject(i) 119 notify(i, i, false) 120 } 121 //做一次练习 122 notify(500, 500, true) 123 124 //创建新的叉子 125 for i := uint64(501); i <= 1000; i++ { 126 inject(i) 127 notify(i, i, false) 128 } 129 for i := uint64(1001); i <= 1500; i++ { 130 inject(i) 131 } 132 //处理可用块少于通知块的方案失败 133 notify(2000, 1500, false) 134 135 //通知有关REORG的信息(如果在处理过程中发生,可能会导致丢失的块) 136 notify(1500, 1500, true) 137 138 //创建新的叉子 139 for i := uint64(1501); i <= 2000; i++ { 140 inject(i) 141 notify(i, i, false) 142 } 143 } 144 145 //testchainindexbackend实现chainindexerbackend 146 type testChainIndexBackend struct { 147 t *testing.T 148 indexer *ChainIndexer 149 section, headerCnt, stored uint64 150 processCh chan uint64 151 } 152 153 //断言节验证链索引器的节数是否正确。 154 func (b *testChainIndexBackend) assertSections() { 155 //如果不匹配,继续尝试3秒钟 156 var sections uint64 157 for i := 0; i < 300; i++ { 158 sections, _, _ = b.indexer.Sections() 159 if sections == b.stored { 160 return 161 } 162 time.Sleep(10 * time.Millisecond) 163 } 164 b.t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, b.stored) 165 } 166 167 //断言块需要在新块到达后进行处理调用。如果 168 //failnum<headnum,然后我们将模拟发生REORG的场景 169 //在处理开始并且一个部分的处理失败之后。 170 func (b *testChainIndexBackend) assertBlocks(headNum, failNum uint64) (uint64, bool) { 171 var sections uint64 172 if headNum >= b.indexer.confirmsReq { 173 sections = (headNum + 1 - b.indexer.confirmsReq) / b.indexer.sectionSize 174 if sections > b.stored { 175 //预期已处理的块 176 for expectd := b.stored * b.indexer.sectionSize; expectd < sections*b.indexer.sectionSize; expectd++ { 177 if expectd > failNum { 178 //在处理开始后回滚,不需要更多的处理调用 179 //等待更新完成,以确保处理实际失败 180 var updating bool 181 for i := 0; i < 300; i++ { 182 b.indexer.lock.Lock() 183 updating = b.indexer.knownSections > b.indexer.storedSections 184 b.indexer.lock.Unlock() 185 if !updating { 186 break 187 } 188 time.Sleep(10 * time.Millisecond) 189 } 190 if updating { 191 b.t.Fatalf("update did not finish") 192 } 193 sections = expectd / b.indexer.sectionSize 194 break 195 } 196 select { 197 case <-time.After(10 * time.Second): 198 b.t.Fatalf("Expected processed block #%d, got nothing", expectd) 199 case processed := <-b.processCh: 200 if processed != expectd { 201 b.t.Errorf("Expected processed block #%d, got #%d", expectd, processed) 202 } 203 } 204 } 205 b.stored = sections 206 } 207 } 208 if b.stored == 0 { 209 return 0, false 210 } 211 return b.stored*b.indexer.sectionSize - 1, true 212 } 213 214 func (b *testChainIndexBackend) reorg(headNum uint64) uint64 { 215 firstChanged := headNum / b.indexer.sectionSize 216 if firstChanged < b.stored { 217 b.stored = firstChanged 218 } 219 return b.stored * b.indexer.sectionSize 220 } 221 222 func (b *testChainIndexBackend) Reset(ctx context.Context, section uint64, prevHead common.Hash) error { 223 b.section = section 224 b.headerCnt = 0 225 return nil 226 } 227 228 func (b *testChainIndexBackend) Process(ctx context.Context, header *types.Header) error { 229 b.headerCnt++ 230 if b.headerCnt > b.indexer.sectionSize { 231 b.t.Error("Processing too many headers") 232 } 233 //t.processch<-header.number.uint64()。 234 select { 235 case <-time.After(10 * time.Second): 236 b.t.Fatal("Unexpected call to Process") 237 case b.processCh <- header.Number.Uint64(): 238 } 239 return nil 240 } 241 242 func (b *testChainIndexBackend) Commit() error { 243 if b.headerCnt != b.indexer.sectionSize { 244 b.t.Error("Not enough headers processed") 245 } 246 return nil 247 }