github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/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/ethereum/go-ethereum/consensus/ethash" 25 "github.com/ethereum/go-ethereum/core" 26 "github.com/ethereum/go-ethereum/core/rawdb" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/light" 29 "github.com/ethereum/go-ethereum/p2p/enode" 30 "github.com/ethereum/go-ethereum/params" 31 ) 32 33 // verifyImportEvent verifies that one single event arrive on an import channel. 34 func verifyImportEvent(t *testing.T, imported chan interface{}, arrive bool) { 35 if arrive { 36 select { 37 case <-imported: 38 case <-time.After(time.Second): 39 t.Fatalf("import timeout") 40 } 41 } else { 42 select { 43 case <-imported: 44 t.Fatalf("import invoked") 45 case <-time.After(20 * time.Millisecond): 46 } 47 } 48 } 49 50 // verifyImportDone verifies that no more events are arriving on an import channel. 51 func verifyImportDone(t *testing.T, imported chan interface{}) { 52 select { 53 case <-imported: 54 t.Fatalf("extra block imported") 55 case <-time.After(50 * time.Millisecond): 56 } 57 } 58 59 // verifyChainHeight verifies the chain height is as expected. 60 func verifyChainHeight(t *testing.T, fetcher *lightFetcher, height uint64) { 61 local := fetcher.chain.CurrentHeader().Number.Uint64() 62 if local != height { 63 t.Fatalf("chain height mismatch, got %d, want %d", local, height) 64 } 65 } 66 67 func TestSequentialAnnouncementsLes2(t *testing.T) { testSequentialAnnouncements(t, 2) } 68 func TestSequentialAnnouncementsLes3(t *testing.T) { testSequentialAnnouncements(t, 3) } 69 70 func testSequentialAnnouncements(t *testing.T, protocol int) { 71 netconfig := testnetConfig{ 72 blocks: 4, 73 protocol: protocol, 74 nopruning: true, 75 } 76 s, c, teardown := newClientServerEnv(t, netconfig) 77 defer teardown() 78 79 // Create connected peer pair, the initial signal from LES server 80 // is discarded to prevent syncing. 81 p1, _, err := newTestPeerPair("peer", protocol, s.handler, c.handler, true) 82 if err != nil { 83 t.Fatalf("Failed to create peer pair %v", err) 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, the initial signal from LES server 118 // is discarded to prevent syncing. 119 peer, _, err := newTestPeerPair("peer", protocol, s.handler, c.handler, true) 120 if err != nil { 121 t.Fatalf("Failed to create peer pair %v", err) 122 } 123 done := make(chan *types.Header, 1) 124 c.handler.fetcher.newHeadHook = func(header *types.Header) { done <- header } 125 126 // Prepare announcement by latest header. 127 latest := s.backend.Blockchain().CurrentHeader() 128 hash, number := latest.Hash(), latest.Number.Uint64() 129 td := rawdb.ReadTd(s.db, hash, number) 130 131 // Sign the announcement if necessary. 132 announce := announceData{hash, number, td, 0, nil} 133 if peer.cpeer.announceType == announceTypeSigned { 134 announce.sign(s.handler.server.privateKey) 135 } 136 peer.cpeer.sendAnnounce(announce) 137 138 <-done // Wait syncing 139 verifyChainHeight(t, c.handler.fetcher, 4) 140 141 // Send a reorged announcement 142 blocks, _ := core.GenerateChain(rawdb.ReadChainConfig(s.db, s.backend.Blockchain().Genesis().Hash()), s.backend.Blockchain().GetBlockByNumber(3), 143 ethash.NewFaker(), s.db, 2, func(i int, gen *core.BlockGen) { 144 gen.OffsetTime(-9) // higher block difficulty 145 }) 146 s.backend.Blockchain().InsertChain(blocks) 147 148 <-done // Wait syncing 149 verifyChainHeight(t, c.handler.fetcher, 5) 150 } 151 152 func TestTrustedAnnouncementsLes2(t *testing.T) { testTrustedAnnouncement(t, 2) } 153 func TestTrustedAnnouncementsLes3(t *testing.T) { testTrustedAnnouncement(t, 3) } 154 155 func testTrustedAnnouncement(t *testing.T, protocol int) { 156 //log.Root().SetHandler(log.LvlFilterHandler(log.LvlDebug, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 157 var ( 158 servers []*testServer 159 teardowns []func() 160 nodes []*enode.Node 161 ids []string 162 cpeers []*clientPeer 163 speers []*serverPeer 164 165 config = light.TestServerIndexerConfig 166 waitIndexers = func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 167 for { 168 cs, _, _ := cIndexer.Sections() 169 bts, _, _ := btIndexer.Sections() 170 if cs >= 2 && bts >= 2 { 171 break 172 } 173 time.Sleep(10 * time.Millisecond) 174 } 175 } 176 ) 177 for i := 0; i < 4; i++ { 178 s, n, teardown := newTestServerPeer(t, int(2*config.ChtSize+config.ChtConfirms), protocol, waitIndexers) 179 180 servers = append(servers, s) 181 nodes = append(nodes, n) 182 teardowns = append(teardowns, teardown) 183 184 // A half of them are trusted servers. 185 if i < 2 { 186 ids = append(ids, n.String()) 187 } 188 } 189 netconfig := testnetConfig{ 190 protocol: protocol, 191 nopruning: true, 192 ulcServers: ids, 193 ulcFraction: 60, 194 } 195 _, c, teardown := newClientServerEnv(t, netconfig) 196 defer teardown() 197 defer func() { 198 for i := 0; i < len(teardowns); i++ { 199 teardowns[i]() 200 } 201 }() 202 203 // Register the assembled checkpoint as hardcoded one. 204 head := servers[0].chtIndexer.SectionHead(0) 205 cp := ¶ms.TrustedCheckpoint{ 206 SectionIndex: 0, 207 SectionHead: head, 208 CHTRoot: light.GetChtRoot(servers[0].db, 0, head), 209 BloomRoot: light.GetBloomTrieRoot(servers[0].db, 0, head), 210 } 211 c.handler.checkpoint = cp 212 c.handler.backend.blockchain.AddTrustedCheckpoint(cp) 213 214 // Connect all server instances. 215 for i := 0; i < len(servers); i++ { 216 sp, cp, err := connect(servers[i].handler, nodes[i].ID(), c.handler, protocol, true) 217 if err != nil { 218 t.Fatalf("connect server and client failed, err %s", err) 219 } 220 cpeers = append(cpeers, cp) 221 speers = append(speers, sp) 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{config.ChtSize + config.ChtConfirms}, config.ChtSize+config.ChtConfirms, func() { <-newHead }) // ULC-style light syncing, rollback untrusted headers 249 check([]uint64{2*config.ChtSize + config.ChtConfirms}, 2*config.ChtSize+config.ChtConfirms, 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, the initial signal from LES server 266 // is discarded to prevent syncing. 267 peer, _, err := newTestPeerPair("peer", lpv3, s.handler, c.handler, true) 268 if err != nil { 269 t.Fatalf("Failed to create peer pair %v", err) 270 } 271 done := make(chan *types.Header, 1) 272 c.handler.fetcher.newHeadHook = func(header *types.Header) { done <- header } 273 274 // Prepare announcement by latest header. 275 headerOne := s.backend.Blockchain().GetHeaderByNumber(1) 276 hash, number := headerOne.Hash(), headerOne.Number.Uint64() 277 td := big.NewInt(params.GenesisDifficulty.Int64() + 200) // bad td 278 279 // Sign the announcement if necessary. 280 announce := announceData{hash, number, td, 0, nil} 281 if peer.cpeer.announceType == announceTypeSigned { 282 announce.sign(s.handler.server.privateKey) 283 } 284 peer.cpeer.sendAnnounce(announce) 285 <-done // Wait syncing 286 287 // Ensure the bad peer is evicited 288 if c.handler.backend.peers.len() != 0 { 289 t.Fatalf("Failed to evict invalid peer") 290 } 291 }