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