github.com/ylsGit/go-ethereum@v1.6.5/light/lightchain_test.go (about) 1 // Copyright 2016 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 light 18 19 import ( 20 "context" 21 "fmt" 22 "math/big" 23 "testing" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/consensus/ethash" 27 "github.com/ethereum/go-ethereum/core" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/ethdb" 30 "github.com/ethereum/go-ethereum/event" 31 "github.com/ethereum/go-ethereum/params" 32 ) 33 34 // So we can deterministically seed different blockchains 35 var ( 36 canonicalSeed = 1 37 forkSeed = 2 38 ) 39 40 // makeHeaderChain creates a deterministic chain of headers rooted at parent. 41 func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header { 42 blocks, _ := core.GenerateChain(params.TestChainConfig, types.NewBlockWithHeader(parent), db, n, func(i int, b *core.BlockGen) { 43 b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)}) 44 }) 45 headers := make([]*types.Header, len(blocks)) 46 for i, block := range blocks { 47 headers[i] = block.Header() 48 } 49 return headers 50 } 51 52 // newCanonical creates a chain database, and injects a deterministic canonical 53 // chain. Depending on the full flag, if creates either a full block chain or a 54 // header only chain. 55 func newCanonical(n int) (ethdb.Database, *LightChain, error) { 56 db, _ := ethdb.NewMemDatabase() 57 gspec := core.Genesis{Config: params.TestChainConfig} 58 genesis := gspec.MustCommit(db) 59 blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFaker(), new(event.TypeMux)) 60 61 // Create and inject the requested chain 62 if n == 0 { 63 return db, blockchain, nil 64 } 65 // Header-only chain requested 66 headers := makeHeaderChain(genesis.Header(), n, db, canonicalSeed) 67 _, err := blockchain.InsertHeaderChain(headers, 1) 68 return db, blockchain, err 69 } 70 71 // newTestLightChain creates a LightChain that doesn't validate anything. 72 func newTestLightChain() *LightChain { 73 db, _ := ethdb.NewMemDatabase() 74 gspec := &core.Genesis{ 75 Difficulty: big.NewInt(1), 76 Config: params.TestChainConfig, 77 } 78 gspec.MustCommit(db) 79 lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), new(event.TypeMux)) 80 if err != nil { 81 panic(err) 82 } 83 return lc 84 } 85 86 // Test fork of length N starting from block i 87 func testFork(t *testing.T, LightChain *LightChain, i, n int, comparator func(td1, td2 *big.Int)) { 88 // Copy old chain up to #i into a new db 89 db, LightChain2, err := newCanonical(i) 90 if err != nil { 91 t.Fatal("could not make new canonical in testFork", err) 92 } 93 // Assert the chains have the same header/block at #i 94 var hash1, hash2 common.Hash 95 hash1 = LightChain.GetHeaderByNumber(uint64(i)).Hash() 96 hash2 = LightChain2.GetHeaderByNumber(uint64(i)).Hash() 97 if hash1 != hash2 { 98 t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", i, hash2, hash1) 99 } 100 // Extend the newly created chain 101 var ( 102 headerChainB []*types.Header 103 ) 104 headerChainB = makeHeaderChain(LightChain2.CurrentHeader(), n, db, forkSeed) 105 if _, err := LightChain2.InsertHeaderChain(headerChainB, 1); err != nil { 106 t.Fatalf("failed to insert forking chain: %v", err) 107 } 108 // Sanity check that the forked chain can be imported into the original 109 var tdPre, tdPost *big.Int 110 111 tdPre = LightChain.GetTdByHash(LightChain.CurrentHeader().Hash()) 112 if err := testHeaderChainImport(headerChainB, LightChain); err != nil { 113 t.Fatalf("failed to import forked header chain: %v", err) 114 } 115 tdPost = LightChain.GetTdByHash(headerChainB[len(headerChainB)-1].Hash()) 116 // Compare the total difficulties of the chains 117 comparator(tdPre, tdPost) 118 } 119 120 func printChain(bc *LightChain) { 121 for i := bc.CurrentHeader().Number.Uint64(); i > 0; i-- { 122 b := bc.GetHeaderByNumber(uint64(i)) 123 fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty) 124 } 125 } 126 127 // testHeaderChainImport tries to process a chain of header, writing them into 128 // the database if successful. 129 func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error { 130 for _, header := range chain { 131 // Try and validate the header 132 if err := lightchain.engine.VerifyHeader(lightchain.hc, header, true); err != nil { 133 return err 134 } 135 // Manually insert the header into the database, but don't reorganize (allows subsequent testing) 136 lightchain.mu.Lock() 137 core.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, lightchain.GetTdByHash(header.ParentHash))) 138 core.WriteHeader(lightchain.chainDb, header) 139 lightchain.mu.Unlock() 140 } 141 return nil 142 } 143 144 // Tests that given a starting canonical chain of a given size, it can be extended 145 // with various length chains. 146 func TestExtendCanonicalHeaders(t *testing.T) { 147 length := 5 148 149 // Make first chain starting from genesis 150 _, processor, err := newCanonical(length) 151 if err != nil { 152 t.Fatalf("failed to make new canonical chain: %v", err) 153 } 154 // Define the difficulty comparator 155 better := func(td1, td2 *big.Int) { 156 if td2.Cmp(td1) <= 0 { 157 t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1) 158 } 159 } 160 // Start fork from current height 161 testFork(t, processor, length, 1, better) 162 testFork(t, processor, length, 2, better) 163 testFork(t, processor, length, 5, better) 164 testFork(t, processor, length, 10, better) 165 } 166 167 // Tests that given a starting canonical chain of a given size, creating shorter 168 // forks do not take canonical ownership. 169 func TestShorterForkHeaders(t *testing.T) { 170 length := 10 171 172 // Make first chain starting from genesis 173 _, processor, err := newCanonical(length) 174 if err != nil { 175 t.Fatalf("failed to make new canonical chain: %v", err) 176 } 177 // Define the difficulty comparator 178 worse := func(td1, td2 *big.Int) { 179 if td2.Cmp(td1) >= 0 { 180 t.Errorf("total difficulty mismatch: have %v, expected less than %v", td2, td1) 181 } 182 } 183 // Sum of numbers must be less than `length` for this to be a shorter fork 184 testFork(t, processor, 0, 3, worse) 185 testFork(t, processor, 0, 7, worse) 186 testFork(t, processor, 1, 1, worse) 187 testFork(t, processor, 1, 7, worse) 188 testFork(t, processor, 5, 3, worse) 189 testFork(t, processor, 5, 4, worse) 190 } 191 192 // Tests that given a starting canonical chain of a given size, creating longer 193 // forks do take canonical ownership. 194 func TestLongerForkHeaders(t *testing.T) { 195 length := 10 196 197 // Make first chain starting from genesis 198 _, processor, err := newCanonical(length) 199 if err != nil { 200 t.Fatalf("failed to make new canonical chain: %v", err) 201 } 202 // Define the difficulty comparator 203 better := func(td1, td2 *big.Int) { 204 if td2.Cmp(td1) <= 0 { 205 t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1) 206 } 207 } 208 // Sum of numbers must be greater than `length` for this to be a longer fork 209 testFork(t, processor, 0, 11, better) 210 testFork(t, processor, 0, 15, better) 211 testFork(t, processor, 1, 10, better) 212 testFork(t, processor, 1, 12, better) 213 testFork(t, processor, 5, 6, better) 214 testFork(t, processor, 5, 8, better) 215 } 216 217 // Tests that given a starting canonical chain of a given size, creating equal 218 // forks do take canonical ownership. 219 func TestEqualForkHeaders(t *testing.T) { 220 length := 10 221 222 // Make first chain starting from genesis 223 _, processor, err := newCanonical(length) 224 if err != nil { 225 t.Fatalf("failed to make new canonical chain: %v", err) 226 } 227 // Define the difficulty comparator 228 equal := func(td1, td2 *big.Int) { 229 if td2.Cmp(td1) != 0 { 230 t.Errorf("total difficulty mismatch: have %v, want %v", td2, td1) 231 } 232 } 233 // Sum of numbers must be equal to `length` for this to be an equal fork 234 testFork(t, processor, 0, 10, equal) 235 testFork(t, processor, 1, 9, equal) 236 testFork(t, processor, 2, 8, equal) 237 testFork(t, processor, 5, 5, equal) 238 testFork(t, processor, 6, 4, equal) 239 testFork(t, processor, 9, 1, equal) 240 } 241 242 // Tests that chains missing links do not get accepted by the processor. 243 func TestBrokenHeaderChain(t *testing.T) { 244 // Make chain starting from genesis 245 db, LightChain, err := newCanonical(10) 246 if err != nil { 247 t.Fatalf("failed to make new canonical chain: %v", err) 248 } 249 // Create a forked chain, and try to insert with a missing link 250 chain := makeHeaderChain(LightChain.CurrentHeader(), 5, db, forkSeed)[1:] 251 if err := testHeaderChainImport(chain, LightChain); err == nil { 252 t.Errorf("broken header chain not reported") 253 } 254 } 255 256 func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header { 257 var chain []*types.Header 258 for i, difficulty := range d { 259 header := &types.Header{ 260 Coinbase: common.Address{seed}, 261 Number: big.NewInt(int64(i + 1)), 262 Difficulty: big.NewInt(int64(difficulty)), 263 UncleHash: types.EmptyUncleHash, 264 TxHash: types.EmptyRootHash, 265 ReceiptHash: types.EmptyRootHash, 266 } 267 if i == 0 { 268 header.ParentHash = genesis.Hash() 269 } else { 270 header.ParentHash = chain[i-1].Hash() 271 } 272 chain = append(chain, types.CopyHeader(header)) 273 } 274 return chain 275 } 276 277 type dummyOdr struct { 278 OdrBackend 279 db ethdb.Database 280 } 281 282 func (odr *dummyOdr) Database() ethdb.Database { 283 return odr.db 284 } 285 286 func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error { 287 return nil 288 } 289 290 // Tests that reorganizing a long difficult chain after a short easy one 291 // overwrites the canonical numbers and links in the database. 292 func TestReorgLongHeaders(t *testing.T) { 293 testReorg(t, []int{1, 2, 4}, []int{1, 2, 3, 4}, 10) 294 } 295 296 // Tests that reorganizing a short difficult chain after a long easy one 297 // overwrites the canonical numbers and links in the database. 298 func TestReorgShortHeaders(t *testing.T) { 299 testReorg(t, []int{1, 2, 3, 4}, []int{1, 10}, 11) 300 } 301 302 func testReorg(t *testing.T, first, second []int, td int64) { 303 bc := newTestLightChain() 304 305 // Insert an easy and a difficult chain afterwards 306 bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1) 307 bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1) 308 // Check that the chain is valid number and link wise 309 prev := bc.CurrentHeader() 310 for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) { 311 if prev.ParentHash != header.Hash() { 312 t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash()) 313 } 314 } 315 // Make sure the chain total difficulty is the correct one 316 want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td)) 317 if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 { 318 t.Errorf("total difficulty mismatch: have %v, want %v", have, want) 319 } 320 } 321 322 // Tests that the insertion functions detect banned hashes. 323 func TestBadHeaderHashes(t *testing.T) { 324 bc := newTestLightChain() 325 326 // Create a chain, ban a hash and try to import 327 var err error 328 headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10) 329 core.BadHashes[headers[2].Hash()] = true 330 if _, err = bc.InsertHeaderChain(headers, 1); err != core.ErrBlacklistedHash { 331 t.Errorf("error mismatch: have: %v, want %v", err, core.ErrBlacklistedHash) 332 } 333 } 334 335 // Tests that bad hashes are detected on boot, and the chan rolled back to a 336 // good state prior to the bad hash. 337 func TestReorgBadHeaderHashes(t *testing.T) { 338 bc := newTestLightChain() 339 340 // Create a chain, import and ban aferwards 341 headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) 342 343 if _, err := bc.InsertHeaderChain(headers, 1); err != nil { 344 t.Fatalf("failed to import headers: %v", err) 345 } 346 if bc.CurrentHeader().Hash() != headers[3].Hash() { 347 t.Errorf("last header hash mismatch: have: %x, want %x", bc.CurrentHeader().Hash(), headers[3].Hash()) 348 } 349 core.BadHashes[headers[3].Hash()] = true 350 defer func() { delete(core.BadHashes, headers[3].Hash()) }() 351 352 // Create a new LightChain and check that it rolled back the state. 353 ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux)) 354 if err != nil { 355 t.Fatalf("failed to create new chain manager: %v", err) 356 } 357 if ncm.CurrentHeader().Hash() != headers[2].Hash() { 358 t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash()) 359 } 360 }