github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/les/sync_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 "fmt" 21 "math/big" 22 "testing" 23 "time" 24 25 "github.com/ethereum/go-ethereum/accounts/abi/bind" 26 "github.com/ethereum/go-ethereum/core" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/light" 30 "github.com/ethereum/go-ethereum/params" 31 ) 32 33 // Test light syncing which will download all headers from genesis. 34 func TestLightSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 0) } 35 36 // Test legacy checkpoint syncing which will download tail headers 37 // based on a hardcoded checkpoint. 38 func TestLegacyCheckpointSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 1) } 39 40 // Test checkpoint syncing which will download tail headers based 41 // on a verified checkpoint. 42 func TestCheckpointSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 2) } 43 44 func testCheckpointSyncing(t *testing.T, protocol int, syncMode int) { 45 config := light.TestServerIndexerConfig 46 47 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 48 for { 49 cs, _, _ := cIndexer.Sections() 50 bts, _, _ := btIndexer.Sections() 51 if cs >= 1 && bts >= 1 { 52 break 53 } 54 time.Sleep(10 * time.Millisecond) 55 } 56 } 57 // Generate 128+1 blocks (totally 1 CHT section) 58 netconfig := testnetConfig{ 59 blocks: int(config.ChtSize + config.ChtConfirms), 60 protocol: protocol, 61 indexFn: waitIndexers, 62 nopruning: true, 63 } 64 server, client, tearDown := newClientServerEnv(t, netconfig) 65 defer tearDown() 66 67 expected := config.ChtSize + config.ChtConfirms 68 69 // Checkpoint syncing or legacy checkpoint syncing. 70 if syncMode == 1 || syncMode == 2 { 71 // Assemble checkpoint 0 72 s, _, head := server.chtIndexer.Sections() 73 cp := ¶ms.TrustedCheckpoint{ 74 SectionIndex: 0, 75 SectionHead: head, 76 CHTRoot: light.GetChtRoot(server.db, s-1, head), 77 BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), 78 } 79 if syncMode == 1 { 80 // Register the assembled checkpoint as hardcoded one. 81 client.handler.checkpoint = cp 82 client.handler.backend.blockchain.AddTrustedCheckpoint(cp) 83 } else { 84 // Register the assembled checkpoint into oracle. 85 header := server.backend.Blockchain().CurrentHeader() 86 87 data := append([]byte{0x19, 0x00}, append(oracleAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) 88 sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) 89 sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 90 auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337)) 91 if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(auth, cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil { 92 t.Error("register checkpoint failed", err) 93 } 94 server.backend.Commit() 95 96 // Wait for the checkpoint registration 97 for { 98 _, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil) 99 if err != nil || hash == [32]byte{} { 100 time.Sleep(10 * time.Millisecond) 101 continue 102 } 103 break 104 } 105 expected += 1 106 } 107 } 108 109 done := make(chan error) 110 client.handler.syncEnd = func(header *types.Header) { 111 if header.Number.Uint64() == expected { 112 done <- nil 113 } else { 114 done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number) 115 } 116 } 117 118 // Create connected peer pair. 119 peer1, peer2, err := newTestPeerPair("peer", protocol, server.handler, client.handler, false) 120 if err != nil { 121 t.Fatalf("Failed to connect testing peers %v", err) 122 } 123 defer peer1.close() 124 defer peer2.close() 125 126 select { 127 case err := <-done: 128 if err != nil { 129 t.Error("sync failed", err) 130 } 131 return 132 case <-time.NewTimer(10 * time.Second).C: 133 t.Error("checkpoint syncing timeout") 134 } 135 } 136 137 func TestMissOracleBackendLES3(t *testing.T) { testMissOracleBackend(t, true, lpv3) } 138 func TestMissOracleBackendNoCheckpointLES3(t *testing.T) { testMissOracleBackend(t, false, lpv3) } 139 140 func testMissOracleBackend(t *testing.T, hasCheckpoint bool, protocol int) { 141 config := light.TestServerIndexerConfig 142 143 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 144 for { 145 cs, _, _ := cIndexer.Sections() 146 bts, _, _ := btIndexer.Sections() 147 if cs >= 1 && bts >= 1 { 148 break 149 } 150 time.Sleep(10 * time.Millisecond) 151 } 152 } 153 // Generate 128+1 blocks (totally 1 CHT section) 154 netconfig := testnetConfig{ 155 blocks: int(config.ChtSize + config.ChtConfirms), 156 protocol: protocol, 157 indexFn: waitIndexers, 158 nopruning: true, 159 } 160 server, client, tearDown := newClientServerEnv(t, netconfig) 161 defer tearDown() 162 163 expected := config.ChtSize + config.ChtConfirms 164 165 s, _, head := server.chtIndexer.Sections() 166 cp := ¶ms.TrustedCheckpoint{ 167 SectionIndex: 0, 168 SectionHead: head, 169 CHTRoot: light.GetChtRoot(server.db, s-1, head), 170 BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), 171 } 172 // Register the assembled checkpoint into oracle. 173 header := server.backend.Blockchain().CurrentHeader() 174 175 data := append([]byte{0x19, 0x00}, append(oracleAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) 176 sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) 177 sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 178 auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337)) 179 if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(auth, cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil { 180 t.Error("register checkpoint failed", err) 181 } 182 server.backend.Commit() 183 184 // Wait for the checkpoint registration 185 for { 186 _, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil) 187 if err != nil || hash == [32]byte{} { 188 time.Sleep(100 * time.Millisecond) 189 continue 190 } 191 break 192 } 193 expected += 1 194 195 // Explicitly set the oracle as nil. In normal use case it can happen 196 // that user wants to unlock something which blocks the oracle backend 197 // initialisation. But at the same time syncing starts. 198 // 199 // See https://github.com/ethereum/go-ethereum/issues/20097 for more detail. 200 // 201 // In this case, client should run light sync or legacy checkpoint sync 202 // if hardcoded checkpoint is configured. 203 client.handler.backend.oracle = nil 204 205 // For some private networks it can happen checkpoint syncing is enabled 206 // but there is no hardcoded checkpoint configured. 207 if hasCheckpoint { 208 client.handler.checkpoint = cp 209 client.handler.backend.blockchain.AddTrustedCheckpoint(cp) 210 } 211 212 done := make(chan error) 213 client.handler.syncEnd = func(header *types.Header) { 214 if header.Number.Uint64() == expected { 215 done <- nil 216 } else { 217 done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number) 218 } 219 } 220 // Create connected peer pair. 221 if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil { 222 t.Fatalf("Failed to connect testing peers %v", err) 223 } 224 select { 225 case err := <-done: 226 if err != nil { 227 t.Error("sync failed", err) 228 } 229 return 230 case <-time.NewTimer(10 * time.Second).C: 231 t.Error("checkpoint syncing timeout") 232 } 233 } 234 235 func TestSyncFromConfiguredCheckpointLES3(t *testing.T) { testSyncFromConfiguredCheckpoint(t, lpv3) } 236 237 func testSyncFromConfiguredCheckpoint(t *testing.T, protocol int) { 238 config := light.TestServerIndexerConfig 239 240 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 241 for { 242 cs, _, _ := cIndexer.Sections() 243 bts, _, _ := btIndexer.Sections() 244 if cs >= 2 && bts >= 2 { 245 break 246 } 247 time.Sleep(10 * time.Millisecond) 248 } 249 } 250 // Generate 256+1 blocks (totally 2 CHT sections) 251 netconfig := testnetConfig{ 252 blocks: int(2*config.ChtSize + config.ChtConfirms), 253 protocol: protocol, 254 indexFn: waitIndexers, 255 nopruning: true, 256 } 257 server, client, tearDown := newClientServerEnv(t, netconfig) 258 defer tearDown() 259 260 // Configure the local checkpoint(the first section) 261 head := server.handler.blockchain.GetHeaderByNumber(config.ChtSize - 1).Hash() 262 cp := ¶ms.TrustedCheckpoint{ 263 SectionIndex: 0, 264 SectionHead: head, 265 CHTRoot: light.GetChtRoot(server.db, 0, head), 266 BloomRoot: light.GetBloomTrieRoot(server.db, 0, head), 267 } 268 client.handler.backend.config.SyncFromCheckpoint = true 269 client.handler.backend.config.Checkpoint = cp 270 client.handler.checkpoint = cp 271 client.handler.backend.blockchain.AddTrustedCheckpoint(cp) 272 273 var ( 274 start = make(chan error, 1) 275 end = make(chan error, 1) 276 expectStart = config.ChtSize - 1 277 expectEnd = 2*config.ChtSize + config.ChtConfirms 278 ) 279 client.handler.syncStart = func(header *types.Header) { 280 if header.Number.Uint64() == expectStart { 281 start <- nil 282 } else { 283 start <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectStart, header.Number) 284 } 285 } 286 client.handler.syncEnd = func(header *types.Header) { 287 if header.Number.Uint64() == expectEnd { 288 end <- nil 289 } else { 290 end <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectEnd, header.Number) 291 } 292 } 293 // Create connected peer pair. 294 if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil { 295 t.Fatalf("Failed to connect testing peers %v", err) 296 } 297 298 select { 299 case err := <-start: 300 if err != nil { 301 t.Error("sync failed", err) 302 } 303 return 304 case <-time.NewTimer(10 * time.Second).C: 305 t.Error("checkpoint syncing timeout") 306 } 307 308 select { 309 case err := <-end: 310 if err != nil { 311 t.Error("sync failed", err) 312 } 313 return 314 case <-time.NewTimer(10 * time.Second).C: 315 t.Error("checkpoint syncing timeout") 316 } 317 } 318 319 func TestSyncAll(t *testing.T) { testSyncAll(t, lpv3) } 320 321 func testSyncAll(t *testing.T, protocol int) { 322 config := light.TestServerIndexerConfig 323 324 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 325 for { 326 cs, _, _ := cIndexer.Sections() 327 bts, _, _ := btIndexer.Sections() 328 if cs >= 2 && bts >= 2 { 329 break 330 } 331 time.Sleep(10 * time.Millisecond) 332 } 333 } 334 // Generate 256+1 blocks (totally 2 CHT sections) 335 netconfig := testnetConfig{ 336 blocks: int(2*config.ChtSize + config.ChtConfirms), 337 protocol: protocol, 338 indexFn: waitIndexers, 339 nopruning: true, 340 } 341 server, client, tearDown := newClientServerEnv(t, netconfig) 342 defer tearDown() 343 344 client.handler.backend.config.SyncFromCheckpoint = true 345 346 var ( 347 start = make(chan error, 1) 348 end = make(chan error, 1) 349 expectStart = uint64(0) 350 expectEnd = 2*config.ChtSize + config.ChtConfirms 351 ) 352 client.handler.syncStart = func(header *types.Header) { 353 if header.Number.Uint64() == expectStart { 354 start <- nil 355 } else { 356 start <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectStart, header.Number) 357 } 358 } 359 client.handler.syncEnd = func(header *types.Header) { 360 if header.Number.Uint64() == expectEnd { 361 end <- nil 362 } else { 363 end <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectEnd, header.Number) 364 } 365 } 366 // Create connected peer pair. 367 if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler, false); err != nil { 368 t.Fatalf("Failed to connect testing peers %v", err) 369 } 370 371 select { 372 case err := <-start: 373 if err != nil { 374 t.Error("sync failed", err) 375 } 376 return 377 case <-time.NewTimer(10 * time.Second).C: 378 t.Error("checkpoint syncing timeout") 379 } 380 381 select { 382 case err := <-end: 383 if err != nil { 384 t.Error("sync failed", err) 385 } 386 return 387 case <-time.NewTimer(10 * time.Second).C: 388 t.Error("checkpoint syncing timeout") 389 } 390 }