github.com/cryptogateway/go-paymex@v0.0.0-20210204174735-96277fb1e602/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/cryptogateway/go-paymex/accounts/abi/bind" 26 "github.com/cryptogateway/go-paymex/core" 27 "github.com/cryptogateway/go-paymex/core/types" 28 "github.com/cryptogateway/go-paymex/crypto" 29 "github.com/cryptogateway/go-paymex/light" 30 "github.com/cryptogateway/go-paymex/params" 31 ) 32 33 // Test light syncing which will download all headers from genesis. 34 func TestLightSyncingLes3(t *testing.T) { testCheckpointSyncing(t, 3, 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, 3, 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, 3, 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 server, client, tearDown := newClientServerEnv(t, int(config.ChtSize+config.ChtConfirms), protocol, waitIndexers, nil, 0, false, false, true) 59 defer tearDown() 60 61 expected := config.ChtSize + config.ChtConfirms 62 63 // Checkpoint syncing or legacy checkpoint syncing. 64 if syncMode == 1 || syncMode == 2 { 65 // Assemble checkpoint 0 66 s, _, head := server.chtIndexer.Sections() 67 cp := ¶ms.TrustedCheckpoint{ 68 SectionIndex: 0, 69 SectionHead: head, 70 CHTRoot: light.GetChtRoot(server.db, s-1, head), 71 BloomRoot: light.GetBloomTrieRoot(server.db, s-1, head), 72 } 73 if syncMode == 1 { 74 // Register the assembled checkpoint as hardcoded one. 75 client.handler.checkpoint = cp 76 client.handler.backend.blockchain.AddTrustedCheckpoint(cp) 77 } else { 78 // Register the assembled checkpoint into oracle. 79 header := server.backend.Blockchain().CurrentHeader() 80 81 data := append([]byte{0x19, 0x00}, append(registrarAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...) 82 sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey) 83 sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 84 auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337)) 85 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 { 86 t.Error("register checkpoint failed", err) 87 } 88 server.backend.Commit() 89 90 // Wait for the checkpoint registration 91 for { 92 _, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil) 93 if err != nil || hash == [32]byte{} { 94 time.Sleep(10 * time.Millisecond) 95 continue 96 } 97 break 98 } 99 expected += 1 100 } 101 } 102 103 done := make(chan error) 104 client.handler.syncEnd = func(header *types.Header) { 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 128+1 blocks (totally 1 CHT section) 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/cryptogateway/go-paymex/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.syncEnd = func(header *types.Header) { 202 if header.Number.Uint64() == expected { 203 done <- nil 204 } else { 205 done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number) 206 } 207 } 208 // Create connected peer pair. 209 if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil { 210 t.Fatalf("Failed to connect testing peers %v", err) 211 } 212 select { 213 case err := <-done: 214 if err != nil { 215 t.Error("sync failed", err) 216 } 217 return 218 case <-time.NewTimer(10 * time.Second).C: 219 t.Error("checkpoint syncing timeout") 220 } 221 } 222 223 func TestSyncFromConfiguredCheckpoint(t *testing.T) { 224 config := light.TestServerIndexerConfig 225 226 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 227 for { 228 cs, _, _ := cIndexer.Sections() 229 bts, _, _ := btIndexer.Sections() 230 if cs >= 2 && bts >= 2 { 231 break 232 } 233 time.Sleep(10 * time.Millisecond) 234 } 235 } 236 // Generate 256+1 blocks (totally 2 CHT sections) 237 server, client, tearDown := newClientServerEnv(t, int(2*config.ChtSize+config.ChtConfirms), 3, waitIndexers, nil, 0, false, false, true) 238 defer tearDown() 239 240 // Configure the local checkpoint(the first section) 241 head := server.handler.blockchain.GetHeaderByNumber(config.ChtSize - 1).Hash() 242 cp := ¶ms.TrustedCheckpoint{ 243 SectionIndex: 0, 244 SectionHead: head, 245 CHTRoot: light.GetChtRoot(server.db, 0, head), 246 BloomRoot: light.GetBloomTrieRoot(server.db, 0, head), 247 } 248 client.handler.backend.config.SyncFromCheckpoint = true 249 client.handler.backend.config.Checkpoint = cp 250 client.handler.checkpoint = cp 251 client.handler.backend.blockchain.AddTrustedCheckpoint(cp) 252 253 var ( 254 start = make(chan error, 1) 255 end = make(chan error, 1) 256 expectStart = config.ChtSize - 1 257 expectEnd = 2*config.ChtSize + config.ChtConfirms 258 ) 259 client.handler.syncStart = func(header *types.Header) { 260 if header.Number.Uint64() == expectStart { 261 start <- nil 262 } else { 263 start <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectStart, header.Number) 264 } 265 } 266 client.handler.syncEnd = func(header *types.Header) { 267 if header.Number.Uint64() == expectEnd { 268 end <- nil 269 } else { 270 end <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectEnd, header.Number) 271 } 272 } 273 // Create connected peer pair. 274 if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil { 275 t.Fatalf("Failed to connect testing peers %v", err) 276 } 277 278 select { 279 case err := <-start: 280 if err != nil { 281 t.Error("sync failed", err) 282 } 283 return 284 case <-time.NewTimer(10 * time.Second).C: 285 t.Error("checkpoint syncing timeout") 286 } 287 288 select { 289 case err := <-end: 290 if err != nil { 291 t.Error("sync failed", err) 292 } 293 return 294 case <-time.NewTimer(10 * time.Second).C: 295 t.Error("checkpoint syncing timeout") 296 } 297 } 298 299 func TestSyncAll(t *testing.T) { 300 config := light.TestServerIndexerConfig 301 302 waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) { 303 for { 304 cs, _, _ := cIndexer.Sections() 305 bts, _, _ := btIndexer.Sections() 306 if cs >= 2 && bts >= 2 { 307 break 308 } 309 time.Sleep(10 * time.Millisecond) 310 } 311 } 312 // Generate 256+1 blocks (totally 2 CHT sections) 313 server, client, tearDown := newClientServerEnv(t, int(2*config.ChtSize+config.ChtConfirms), 3, waitIndexers, nil, 0, false, false, true) 314 defer tearDown() 315 316 client.handler.backend.config.SyncFromCheckpoint = true 317 318 var ( 319 start = make(chan error, 1) 320 end = make(chan error, 1) 321 expectStart = uint64(0) 322 expectEnd = 2*config.ChtSize + config.ChtConfirms 323 ) 324 client.handler.syncStart = func(header *types.Header) { 325 if header.Number.Uint64() == expectStart { 326 start <- nil 327 } else { 328 start <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectStart, header.Number) 329 } 330 } 331 client.handler.syncEnd = func(header *types.Header) { 332 if header.Number.Uint64() == expectEnd { 333 end <- nil 334 } else { 335 end <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectEnd, header.Number) 336 } 337 } 338 // Create connected peer pair. 339 if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil { 340 t.Fatalf("Failed to connect testing peers %v", err) 341 } 342 343 select { 344 case err := <-start: 345 if err != nil { 346 t.Error("sync failed", err) 347 } 348 return 349 case <-time.NewTimer(10 * time.Second).C: 350 t.Error("checkpoint syncing timeout") 351 } 352 353 select { 354 case err := <-end: 355 if err != nil { 356 t.Error("sync failed", err) 357 } 358 return 359 case <-time.NewTimer(10 * time.Second).C: 360 t.Error("checkpoint syncing timeout") 361 } 362 }