github.com/phillinzzz/newBsc@v1.1.6/les/fetcher_test.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package les 18 19 import ( 20 "math/big" 21 "testing" 22 "time" 23 24 "github.com/phillinzzz/newBsc/consensus/ethash" 25 "github.com/phillinzzz/newBsc/core" 26 "github.com/phillinzzz/newBsc/core/rawdb" 27 "github.com/phillinzzz/newBsc/core/types" 28 "github.com/phillinzzz/newBsc/p2p/enode" 29 ) 30 31 // verifyImportEvent verifies that one single event arrive on an import channel. 32 func verifyImportEvent(t *testing.T, imported chan interface{}, arrive bool) { 33 if arrive { 34 select { 35 case <-imported: 36 case <-time.After(time.Second): 37 t.Fatalf("import timeout") 38 } 39 } else { 40 select { 41 case <-imported: 42 t.Fatalf("import invoked") 43 case <-time.After(20 * time.Millisecond): 44 } 45 } 46 } 47 48 // verifyImportDone verifies that no more events are arriving on an import channel. 49 func verifyImportDone(t *testing.T, imported chan interface{}) { 50 select { 51 case <-imported: 52 t.Fatalf("extra block imported") 53 case <-time.After(50 * time.Millisecond): 54 } 55 } 56 57 // verifyChainHeight verifies the chain height is as expected. 58 func verifyChainHeight(t *testing.T, fetcher *lightFetcher, height uint64) { 59 local := fetcher.chain.CurrentHeader().Number.Uint64() 60 if local != height { 61 t.Fatalf("chain height mismatch, got %d, want %d", local, height) 62 } 63 } 64 65 func TestSequentialAnnouncementsLes2(t *testing.T) { testSequentialAnnouncements(t, 2) } 66 func TestSequentialAnnouncementsLes3(t *testing.T) { testSequentialAnnouncements(t, 3) } 67 68 func testSequentialAnnouncements(t *testing.T, protocol int) { 69 netconfig := testnetConfig{ 70 blocks: 4, 71 protocol: protocol, 72 nopruning: true, 73 } 74 s, c, teardown := newClientServerEnv(t, netconfig) 75 defer teardown() 76 77 // Create connected peer pair. 78 c.handler.fetcher.noAnnounce = true // Ignore the first announce from peer which can trigger a resync. 79 p1, _, err := newTestPeerPair("peer", protocol, s.handler, c.handler) 80 if err != nil { 81 t.Fatalf("Failed to create peer pair %v", err) 82 } 83 c.handler.fetcher.noAnnounce = false 84 85 importCh := make(chan interface{}) 86 c.handler.fetcher.newHeadHook = func(header *types.Header) { 87 importCh <- header 88 } 89 for i := uint64(1); i <= s.backend.Blockchain().CurrentHeader().Number.Uint64(); i++ { 90 header := s.backend.Blockchain().GetHeaderByNumber(i) 91 hash, number := header.Hash(), header.Number.Uint64() 92 td := rawdb.ReadTd(s.db, hash, number) 93 94 announce := announceData{hash, number, td, 0, nil} 95 if p1.cpeer.announceType == announceTypeSigned { 96 announce.sign(s.handler.server.privateKey) 97 } 98 p1.cpeer.sendAnnounce(announce) 99 verifyImportEvent(t, importCh, true) 100 } 101 verifyImportDone(t, importCh) 102 verifyChainHeight(t, c.handler.fetcher, 4) 103 } 104 105 func TestGappedAnnouncementsLes2(t *testing.T) { testGappedAnnouncements(t, 2) } 106 func TestGappedAnnouncementsLes3(t *testing.T) { testGappedAnnouncements(t, 3) } 107 108 func testGappedAnnouncements(t *testing.T, protocol int) { 109 netconfig := testnetConfig{ 110 blocks: 4, 111 protocol: protocol, 112 nopruning: true, 113 } 114 s, c, teardown := newClientServerEnv(t, netconfig) 115 defer teardown() 116 117 // Create connected peer pair. 118 c.handler.fetcher.noAnnounce = true // Ignore the first announce from peer which can trigger a resync. 119 peer, _, err := newTestPeerPair("peer", protocol, s.handler, c.handler) 120 if err != nil { 121 t.Fatalf("Failed to create peer pair %v", err) 122 } 123 c.handler.fetcher.noAnnounce = false 124 125 done := make(chan *types.Header, 1) 126 c.handler.fetcher.newHeadHook = func(header *types.Header) { done <- header } 127 128 // Prepare announcement by latest header. 129 latest := s.backend.Blockchain().CurrentHeader() 130 hash, number := latest.Hash(), latest.Number.Uint64() 131 td := rawdb.ReadTd(s.db, hash, number) 132 133 // Sign the announcement if necessary. 134 announce := announceData{hash, number, td, 0, nil} 135 if peer.cpeer.announceType == announceTypeSigned { 136 announce.sign(s.handler.server.privateKey) 137 } 138 peer.cpeer.sendAnnounce(announce) 139 140 <-done // Wait syncing 141 verifyChainHeight(t, c.handler.fetcher, 4) 142 143 // Send a reorged announcement 144 var newAnno = make(chan struct{}, 1) 145 c.handler.fetcher.noAnnounce = true 146 c.handler.fetcher.newAnnounce = func(*serverPeer, *announceData) { 147 newAnno <- struct{}{} 148 } 149 blocks, _ := core.GenerateChain(rawdb.ReadChainConfig(s.db, s.backend.Blockchain().Genesis().Hash()), s.backend.Blockchain().GetBlockByNumber(3), 150 ethash.NewFaker(), s.db, 2, func(i int, gen *core.BlockGen) { 151 gen.OffsetTime(-9) // higher block difficulty 152 }) 153 s.backend.Blockchain().InsertChain(blocks) 154 <-newAnno 155 c.handler.fetcher.noAnnounce = false 156 c.handler.fetcher.newAnnounce = nil 157 158 latest = blocks[len(blocks)-1].Header() 159 hash, number = latest.Hash(), latest.Number.Uint64() 160 td = rawdb.ReadTd(s.db, hash, number) 161 162 announce = announceData{hash, number, td, 1, nil} 163 if peer.cpeer.announceType == announceTypeSigned { 164 announce.sign(s.handler.server.privateKey) 165 } 166 peer.cpeer.sendAnnounce(announce) 167 168 <-done // Wait syncing 169 verifyChainHeight(t, c.handler.fetcher, 5) 170 } 171 172 func TestTrustedAnnouncementsLes2(t *testing.T) { testTrustedAnnouncement(t, 2) } 173 func TestTrustedAnnouncementsLes3(t *testing.T) { testTrustedAnnouncement(t, 3) } 174 175 func testTrustedAnnouncement(t *testing.T, protocol int) { 176 var ( 177 servers []*testServer 178 teardowns []func() 179 nodes []*enode.Node 180 ids []string 181 cpeers []*clientPeer 182 speers []*serverPeer 183 ) 184 for i := 0; i < 10; i++ { 185 s, n, teardown := newTestServerPeer(t, 10, protocol) 186 187 servers = append(servers, s) 188 nodes = append(nodes, n) 189 teardowns = append(teardowns, teardown) 190 191 // A half of them are trusted servers. 192 if i < 5 { 193 ids = append(ids, n.String()) 194 } 195 } 196 netconfig := testnetConfig{ 197 protocol: protocol, 198 nopruning: true, 199 ulcServers: ids, 200 ulcFraction: 60, 201 } 202 _, c, teardown := newClientServerEnv(t, netconfig) 203 defer teardown() 204 defer func() { 205 for i := 0; i < len(teardowns); i++ { 206 teardowns[i]() 207 } 208 }() 209 210 c.handler.fetcher.noAnnounce = true // Ignore the first announce from peer which can trigger a resync. 211 212 // Connect all server instances. 213 for i := 0; i < len(servers); i++ { 214 sp, cp, err := connect(servers[i].handler, nodes[i].ID(), c.handler, protocol) 215 if err != nil { 216 t.Fatalf("connect server and client failed, err %s", err) 217 } 218 cpeers = append(cpeers, cp) 219 speers = append(speers, sp) 220 } 221 c.handler.fetcher.noAnnounce = false 222 223 newHead := make(chan *types.Header, 1) 224 c.handler.fetcher.newHeadHook = func(header *types.Header) { newHead <- header } 225 226 check := func(height []uint64, expected uint64, callback func()) { 227 for i := 0; i < len(height); i++ { 228 for j := 0; j < len(servers); j++ { 229 h := servers[j].backend.Blockchain().GetHeaderByNumber(height[i]) 230 hash, number := h.Hash(), h.Number.Uint64() 231 td := rawdb.ReadTd(servers[j].db, hash, number) 232 233 // Sign the announcement if necessary. 234 announce := announceData{hash, number, td, 0, nil} 235 p := cpeers[j] 236 if p.announceType == announceTypeSigned { 237 announce.sign(servers[j].handler.server.privateKey) 238 } 239 p.sendAnnounce(announce) 240 } 241 } 242 if callback != nil { 243 callback() 244 } 245 verifyChainHeight(t, c.handler.fetcher, expected) 246 } 247 check([]uint64{1}, 1, func() { <-newHead }) // Sequential announcements 248 check([]uint64{4}, 4, func() { <-newHead }) // ULC-style light syncing, rollback untrusted headers 249 check([]uint64{10}, 10, func() { <-newHead }) // Sync the whole chain. 250 } 251 252 func TestInvalidAnnouncesLES2(t *testing.T) { testInvalidAnnounces(t, lpv2) } 253 func TestInvalidAnnouncesLES3(t *testing.T) { testInvalidAnnounces(t, lpv3) } 254 func TestInvalidAnnouncesLES4(t *testing.T) { testInvalidAnnounces(t, lpv4) } 255 256 func testInvalidAnnounces(t *testing.T, protocol int) { 257 netconfig := testnetConfig{ 258 blocks: 4, 259 protocol: protocol, 260 nopruning: true, 261 } 262 s, c, teardown := newClientServerEnv(t, netconfig) 263 defer teardown() 264 265 // Create connected peer pair. 266 c.handler.fetcher.noAnnounce = true // Ignore the first announce from peer which can trigger a resync. 267 peer, _, err := newTestPeerPair("peer", lpv3, s.handler, c.handler) 268 if err != nil { 269 t.Fatalf("Failed to create peer pair %v", err) 270 } 271 c.handler.fetcher.noAnnounce = false 272 273 done := make(chan *types.Header, 1) 274 c.handler.fetcher.newHeadHook = func(header *types.Header) { done <- header } 275 276 // Prepare announcement by latest header. 277 headerOne := s.backend.Blockchain().GetHeaderByNumber(1) 278 hash, number := headerOne.Hash(), headerOne.Number.Uint64() 279 td := big.NewInt(200) // bad td 280 281 // Sign the announcement if necessary. 282 announce := announceData{hash, number, td, 0, nil} 283 if peer.cpeer.announceType == announceTypeSigned { 284 announce.sign(s.handler.server.privateKey) 285 } 286 peer.cpeer.sendAnnounce(announce) 287 <-done // Wait syncing 288 289 // Ensure the bad peer is evicited 290 if c.handler.backend.peers.len() != 0 { 291 t.Fatalf("Failed to evict invalid peer") 292 } 293 }