github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/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/kisexp/xdchain/accounts/abi/bind" 26 "github.com/kisexp/xdchain/core" 27 "github.com/kisexp/xdchain/crypto" 28 "github.com/kisexp/xdchain/light" 29 "github.com/kisexp/xdchain/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 128+1 blocks (totally 1 CHT sections) 57 server, client, tearDown := newClientServerEnv(t, int(config.ChtSize+config.ChtConfirms), protocol, waitIndexers, nil, 0, false, false, true) 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 auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337)) 84 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 { 85 t.Error("register checkpoint failed", err) 86 } 87 server.backend.Commit() 88 89 // Wait for the checkpoint registration 90 for { 91 _, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil) 92 if err != nil || hash == [32]byte{} { 93 time.Sleep(10 * time.Millisecond) 94 continue 95 } 96 break 97 } 98 expected += 1 99 } 100 } 101 102 done := make(chan error) 103 client.handler.syncDone = func() { 104 header := client.handler.backend.blockchain.CurrentHeader() 105 if header.Number.Uint64() == expected { 106 done <- nil 107 } else { 108 done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number) 109 } 110 } 111 112 // Create connected peer pair. 113 peer1, peer2, err := newTestPeerPair("peer", protocol, server.handler, client.handler) 114 if err != nil { 115 t.Fatalf("Failed to connect testing peers %v", err) 116 } 117 defer peer1.close() 118 defer peer2.close() 119 120 select { 121 case err := <-done: 122 if err != nil { 123 t.Error("sync failed", err) 124 } 125 return 126 case <-time.NewTimer(10 * time.Second).C: 127 t.Error("checkpoint syncing timeout") 128 } 129 } 130 131 func TestMissOracleBackend(t *testing.T) { testMissOracleBackend(t, true) } 132 func TestMissOracleBackendNoCheckpoint(t *testing.T) { testMissOracleBackend(t, false) } 133 134 func testMissOracleBackend(t *testing.T, hasCheckpoint bool) { 135 config := light.TestServerIndexerConfig 136 137 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 138 for { 139 cs, _, _ := cIndexer.Sections() 140 bts, _, _ := btIndexer.Sections() 141 if cs >= 1 && bts >= 1 { 142 break 143 } 144 time.Sleep(10 * time.Millisecond) 145 } 146 } 147 // Generate 512+4 blocks (totally 1 CHT sections) 148 server, client, tearDown := newClientServerEnv(t, int(config.ChtSize+config.ChtConfirms), 3, waitIndexers, nil, 0, false, false, true) 149 defer tearDown() 150 151 expected := config.ChtSize + config.ChtConfirms 152 153 s, _, head := server.chtIndexer.Sections() 154 cp := ¶ms.TrustedCheckpoint{ 155 SectionIndex: 0, 156 SectionHead: head, 157 CHTRoot: light.GetChtRoot(server.db, s-1, head), 158 BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), 159 } 160 // Register the assembled checkpoint into oracle. 161 header := server.backend.Blockchain().CurrentHeader() 162 163 data := append([]byte{0x19, 0x00}, append(registrarAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) 164 sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) 165 sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 166 auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337)) 167 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 { 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/kisexp/xdchain/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 // Create connected peer pair. 210 if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil { 211 t.Fatalf("Failed to connect testing peers %v", err) 212 } 213 select { 214 case err := <-done: 215 if err != nil { 216 t.Error("sync failed", err) 217 } 218 return 219 case <-time.NewTimer(10 * time.Second).C: 220 t.Error("checkpoint syncing timeout") 221 } 222 }