github.com/JFJun/bsc@v1.0.0/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/JFJun/bsc/accounts/abi/bind" 26 "github.com/JFJun/bsc/core" 27 "github.com/JFJun/bsc/crypto" 28 "github.com/JFJun/bsc/light" 29 "github.com/JFJun/bsc/params" 30 ) 31 32 // Test light syncing which will download all headers from genesis. 33 func TestLightSyncingLes3(t *testing.T) { testCheckpointSyncing(t, 3, 0) } 34 35 // Test legacy checkpoint syncing which will download tail headers 36 // based on a hardcoded checkpoint. 37 func TestLegacyCheckpointSyncingLes3(t *testing.T) { testCheckpointSyncing(t, 3, 1) } 38 39 // Test checkpoint syncing which will download tail headers based 40 // on a verified checkpoint. 41 func TestCheckpointSyncingLes3(t *testing.T) { testCheckpointSyncing(t, 3, 2) } 42 43 func testCheckpointSyncing(t *testing.T, protocol int, syncMode int) { 44 config := light.TestServerIndexerConfig 45 46 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 47 for { 48 cs, _, _ := cIndexer.Sections() 49 bts, _, _ := btIndexer.Sections() 50 if cs >= 1 && bts >= 1 { 51 break 52 } 53 time.Sleep(10 * time.Millisecond) 54 } 55 } 56 // Generate 512+4 blocks (totally 1 CHT sections) 57 server, client, tearDown := newClientServerEnv(t, int(config.ChtSize+config.ChtConfirms), protocol, waitIndexers, nil, 0, false, false) 58 defer tearDown() 59 60 expected := config.ChtSize + config.ChtConfirms 61 62 // Checkpoint syncing or legacy checkpoint syncing. 63 if syncMode == 1 || syncMode == 2 { 64 // Assemble checkpoint 0 65 s, _, head := server.chtIndexer.Sections() 66 cp := ¶ms.TrustedCheckpoint{ 67 SectionIndex: 0, 68 SectionHead: head, 69 CHTRoot: light.GetChtRoot(server.db, s-1, head), 70 BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), 71 } 72 if syncMode == 1 { 73 // Register the assembled checkpoint as hardcoded one. 74 client.handler.checkpoint = cp 75 client.handler.backend.blockchain.AddTrustedCheckpoint(cp) 76 } else { 77 // Register the assembled checkpoint into oracle. 78 header := server.backend.Blockchain().CurrentHeader() 79 80 data := append([]byte{0x19, 0x00}, append(registrarAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) 81 sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) 82 sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 83 if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(bind.NewKeyedTransactor(signerKey), cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil { 84 t.Error("register checkpoint failed", err) 85 } 86 server.backend.Commit() 87 88 // Wait for the checkpoint registration 89 for { 90 _, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil) 91 if err != nil || hash == [32]byte{} { 92 time.Sleep(10 * time.Millisecond) 93 continue 94 } 95 break 96 } 97 expected += 1 98 } 99 } 100 101 done := make(chan error) 102 client.handler.syncDone = func() { 103 header := client.handler.backend.blockchain.CurrentHeader() 104 if header.Number.Uint64() == expected { 105 done <- nil 106 } else { 107 done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number) 108 } 109 } 110 111 // Create connected peer pair. 112 peer1, peer2, err := newTestPeerPair("peer", protocol, server.handler, client.handler) 113 if err != nil { 114 t.Fatalf("Failed to connect testing peers %v", err) 115 } 116 defer peer1.close() 117 defer peer2.close() 118 119 select { 120 case err := <-done: 121 if err != nil { 122 t.Error("sync failed", err) 123 } 124 return 125 case <-time.NewTimer(10 * time.Second).C: 126 t.Error("checkpoint syncing timeout") 127 } 128 } 129 130 func TestMissOracleBackend(t *testing.T) { testMissOracleBackend(t, true) } 131 func TestMissOracleBackendNoCheckpoint(t *testing.T) { testMissOracleBackend(t, false) } 132 133 func testMissOracleBackend(t *testing.T, hasCheckpoint bool) { 134 config := light.TestServerIndexerConfig 135 136 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 137 for { 138 cs, _, _ := cIndexer.Sections() 139 bts, _, _ := btIndexer.Sections() 140 if cs >= 1 && bts >= 1 { 141 break 142 } 143 time.Sleep(10 * time.Millisecond) 144 } 145 } 146 // Generate 512+4 blocks (totally 1 CHT sections) 147 server, client, tearDown := newClientServerEnv(t, int(config.ChtSize+config.ChtConfirms), 3, waitIndexers, nil, 0, false, false) 148 defer tearDown() 149 150 expected := config.ChtSize + config.ChtConfirms 151 152 s, _, head := server.chtIndexer.Sections() 153 cp := ¶ms.TrustedCheckpoint{ 154 SectionIndex: 0, 155 SectionHead: head, 156 CHTRoot: light.GetChtRoot(server.db, s-1, head), 157 BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), 158 } 159 // Register the assembled checkpoint into oracle. 160 header := server.backend.Blockchain().CurrentHeader() 161 162 data := append([]byte{0x19, 0x00}, append(registrarAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) 163 sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) 164 sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 165 if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(bind.NewKeyedTransactor(signerKey), cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil { 166 t.Error("register checkpoint failed", err) 167 } 168 server.backend.Commit() 169 170 // Wait for the checkpoint registration 171 for { 172 _, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil) 173 if err != nil || hash == [32]byte{} { 174 time.Sleep(100 * time.Millisecond) 175 continue 176 } 177 break 178 } 179 expected += 1 180 181 // Explicitly set the oracle as nil. In normal use case it can happen 182 // that user wants to unlock something which blocks the oracle backend 183 // initialisation. But at the same time syncing starts. 184 // 185 // See https://github.com/JFJun/bsc/issues/20097 for more detail. 186 // 187 // In this case, client should run light sync or legacy checkpoint sync 188 // if hardcoded checkpoint is configured. 189 client.handler.backend.oracle = nil 190 191 // For some private networks it can happen checkpoint syncing is enabled 192 // but there is no hardcoded checkpoint configured. 193 if hasCheckpoint { 194 client.handler.checkpoint = cp 195 client.handler.backend.blockchain.AddTrustedCheckpoint(cp) 196 } 197 198 done := make(chan error) 199 client.handler.syncDone = func() { 200 header := client.handler.backend.blockchain.CurrentHeader() 201 if header.Number.Uint64() == expected { 202 done <- nil 203 } else { 204 done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number) 205 } 206 } 207 // Create connected peer pair. 208 if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil { 209 t.Fatalf("Failed to connect testing peers %v", err) 210 } 211 select { 212 case err := <-done: 213 if err != nil { 214 t.Error("sync failed", err) 215 } 216 return 217 case <-time.NewTimer(10 * time.Second).C: 218 t.Error("checkpoint syncing timeout") 219 } 220 }