github.com/SwingbyProtocol/go-ethereum@v1.9.7/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/crypto" 28 "github.com/ethereum/go-ethereum/light" 29 "github.com/ethereum/go-ethereum/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 _, err1, _, err2 := newTestPeerPair("peer", protocol, server.handler, client.handler) 113 select { 114 case <-time.After(time.Millisecond * 100): 115 case err := <-err1: 116 t.Fatalf("peer 1 handshake error: %v", err) 117 case err := <-err2: 118 t.Fatalf("peer 2 handshake error: %v", err) 119 } 120 121 select { 122 case err := <-done: 123 if err != nil { 124 t.Error("sync failed", err) 125 } 126 return 127 case <-time.NewTimer(10 * time.Second).C: 128 t.Error("checkpoint syncing timeout") 129 } 130 } 131 132 func TestMissOracleBackend(t *testing.T) { testMissOracleBackend(t, true) } 133 func TestMissOracleBackendNoCheckpoint(t *testing.T) { testMissOracleBackend(t, false) } 134 135 func testMissOracleBackend(t *testing.T, hasCheckpoint bool) { 136 config := light.TestServerIndexerConfig 137 138 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 139 for { 140 cs, _, _ := cIndexer.Sections() 141 bts, _, _ := btIndexer.Sections() 142 if cs >= 1 && bts >= 1 { 143 break 144 } 145 time.Sleep(10 * time.Millisecond) 146 } 147 } 148 // Generate 512+4 blocks (totally 1 CHT sections) 149 server, client, tearDown := newClientServerEnv(t, int(config.ChtSize+config.ChtConfirms), 3, waitIndexers, nil, 0, false, false) 150 defer tearDown() 151 152 expected := config.ChtSize + config.ChtConfirms 153 154 s, _, head := server.chtIndexer.Sections() 155 cp := ¶ms.TrustedCheckpoint{ 156 SectionIndex: 0, 157 SectionHead: head, 158 CHTRoot: light.GetChtRoot(server.db, s-1, head), 159 BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), 160 } 161 // Register the assembled checkpoint into oracle. 162 header := server.backend.Blockchain().CurrentHeader() 163 164 data := append([]byte{0x19, 0x00}, append(registrarAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) 165 sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) 166 sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 167 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 { 168 t.Error("register checkpoint failed", err) 169 } 170 server.backend.Commit() 171 172 // Wait for the checkpoint registration 173 for { 174 _, hash, _, err := server.handler.server.oracle.contract.Contract().GetLatestCheckpoint(nil) 175 if err != nil || hash == [32]byte{} { 176 time.Sleep(100 * time.Millisecond) 177 continue 178 } 179 break 180 } 181 expected += 1 182 183 // Explicitly set the oracle as nil. In normal use case it can happen 184 // that user wants to unlock something which blocks the oracle backend 185 // initialisation. But at the same time syncing starts. 186 // 187 // See https://github.com/ethereum/go-ethereum/issues/20097 for more detail. 188 // 189 // In this case, client should run light sync or legacy checkpoint sync 190 // if hardcoded checkpoint is configured. 191 client.handler.backend.oracle = nil 192 193 // For some private networks it can happen checkpoint syncing is enabled 194 // but there is no hardcoded checkpoint configured. 195 if hasCheckpoint { 196 client.handler.checkpoint = cp 197 client.handler.backend.blockchain.AddTrustedCheckpoint(cp) 198 } 199 200 done := make(chan error) 201 client.handler.syncDone = func() { 202 header := client.handler.backend.blockchain.CurrentHeader() 203 if header.Number.Uint64() == expected { 204 done <- nil 205 } else { 206 done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number) 207 } 208 } 209 210 // Create connected peer pair. 211 _, err1, _, err2 := newTestPeerPair("peer", 2, server.handler, client.handler) 212 select { 213 case <-time.After(time.Millisecond * 100): 214 case err := <-err1: 215 t.Fatalf("peer 1 handshake error: %v", err) 216 case err := <-err2: 217 t.Fatalf("peer 2 handshake error: %v", err) 218 } 219 220 select { 221 case err := <-done: 222 if err != nil { 223 t.Error("sync failed", err) 224 } 225 return 226 case <-time.NewTimer(10 * time.Second).C: 227 t.Error("checkpoint syncing timeout") 228 } 229 }