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