github.com/daethereum/go-dae@v2.2.3+incompatible/les/fetcher_test.go (about) 1 // Copyright 2019 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/daethereum/go-dae/consensus/ethash" 25 "github.com/daethereum/go-dae/core" 26 "github.com/daethereum/go-dae/core/rawdb" 27 "github.com/daethereum/go-dae/core/types" 28 "github.com/daethereum/go-dae/light" 29 "github.com/daethereum/go-dae/p2p/enode" 30 "github.com/daethereum/go-dae/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 164 config = light.TestServerIndexerConfig 165 waitIndexers = func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 166 for { 167 cs, _, _ := cIndexer.Sections() 168 bts, _, _ := btIndexer.Sections() 169 if cs >= 2 && bts >= 2 { 170 break 171 } 172 time.Sleep(10 * time.Millisecond) 173 } 174 } 175 ) 176 for i := 0; i < 4; i++ { 177 s, n, teardown := newTestServerPeer(t, int(2*config.ChtSize+config.ChtConfirms), protocol, waitIndexers) 178 179 servers = append(servers, s) 180 nodes = append(nodes, n) 181 teardowns = append(teardowns, teardown) 182 183 // A half of them are trusted servers. 184 if i < 2 { 185 ids = append(ids, n.String()) 186 } 187 } 188 netconfig := testnetConfig{ 189 protocol: protocol, 190 nopruning: true, 191 ulcServers: ids, 192 ulcFraction: 60, 193 } 194 _, c, teardown := newClientServerEnv(t, netconfig) 195 defer teardown() 196 defer func() { 197 for i := 0; i < len(teardowns); i++ { 198 teardowns[i]() 199 } 200 }() 201 202 // Register the assembled checkpoint as hardcoded one. 203 head := servers[0].chtIndexer.SectionHead(0) 204 cp := ¶ms.TrustedCheckpoint{ 205 SectionIndex: 0, 206 SectionHead: head, 207 CHTRoot: light.GetChtRoot(servers[0].db, 0, head), 208 BloomRoot: light.GetBloomTrieRoot(servers[0].db, 0, head), 209 } 210 c.handler.checkpoint = cp 211 c.handler.backend.blockchain.AddTrustedCheckpoint(cp) 212 213 // Connect all server instances. 214 for i := 0; i < len(servers); i++ { 215 _, cp, err := connect(servers[i].handler, nodes[i].ID(), c.handler, protocol, true) 216 if err != nil { 217 t.Fatalf("connect server and client failed, err %s", err) 218 } 219 cpeers = append(cpeers, cp) 220 } 221 newHead := make(chan *types.Header, 1) 222 c.handler.fetcher.newHeadHook = func(header *types.Header) { newHead <- header } 223 224 check := func(height []uint64, expected uint64, callback func()) { 225 for i := 0; i < len(height); i++ { 226 for j := 0; j < len(servers); j++ { 227 h := servers[j].backend.Blockchain().GetHeaderByNumber(height[i]) 228 hash, number := h.Hash(), h.Number.Uint64() 229 td := rawdb.ReadTd(servers[j].db, hash, number) 230 231 // Sign the announcement if necessary. 232 announce := announceData{hash, number, td, 0, nil} 233 p := cpeers[j] 234 if p.announceType == announceTypeSigned { 235 announce.sign(servers[j].handler.server.privateKey) 236 } 237 p.sendAnnounce(announce) 238 } 239 } 240 if callback != nil { 241 callback() 242 } 243 verifyChainHeight(t, c.handler.fetcher, expected) 244 } 245 check([]uint64{1}, 1, func() { <-newHead }) // Sequential announcements 246 check([]uint64{config.ChtSize + config.ChtConfirms}, config.ChtSize+config.ChtConfirms, func() { <-newHead }) // ULC-style light syncing, rollback untrusted headers 247 check([]uint64{2*config.ChtSize + config.ChtConfirms}, 2*config.ChtSize+config.ChtConfirms, func() { <-newHead }) // Sync the whole chain. 248 } 249 250 func TestInvalidAnnouncesLES2(t *testing.T) { testInvalidAnnounces(t, lpv2) } 251 func TestInvalidAnnouncesLES3(t *testing.T) { testInvalidAnnounces(t, lpv3) } 252 func TestInvalidAnnouncesLES4(t *testing.T) { testInvalidAnnounces(t, lpv4) } 253 254 func testInvalidAnnounces(t *testing.T, protocol int) { 255 netconfig := testnetConfig{ 256 blocks: 4, 257 protocol: protocol, 258 nopruning: true, 259 } 260 s, c, teardown := newClientServerEnv(t, netconfig) 261 defer teardown() 262 263 // Create connected peer pair, the initial signal from LES server 264 // is discarded to prevent syncing. 265 peer, _, err := newTestPeerPair("peer", lpv3, s.handler, c.handler, true) 266 if err != nil { 267 t.Fatalf("Failed to create peer pair %v", err) 268 } 269 done := make(chan *types.Header, 1) 270 c.handler.fetcher.newHeadHook = func(header *types.Header) { done <- header } 271 272 // Prepare announcement by latest header. 273 headerOne := s.backend.Blockchain().GetHeaderByNumber(1) 274 hash, number := headerOne.Hash(), headerOne.Number.Uint64() 275 td := big.NewInt(params.GenesisDifficulty.Int64() + 200) // bad td 276 277 // Sign the announcement if necessary. 278 announce := announceData{hash, number, td, 0, nil} 279 if peer.cpeer.announceType == announceTypeSigned { 280 announce.sign(s.handler.server.privateKey) 281 } 282 peer.cpeer.sendAnnounce(announce) 283 <-done // Wait syncing 284 285 // Ensure the bad peer is evicited 286 if c.handler.backend.peers.len() != 0 { 287 t.Fatalf("Failed to evict invalid peer") 288 } 289 }