github.com/theQRL/go-zond@v0.2.1/zond/downloader/testchain_test.go (about) 1 // Copyright 2018 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 downloader 18 19 import ( 20 "fmt" 21 "math/big" 22 "sync" 23 "time" 24 25 "github.com/theQRL/go-zond/common" 26 "github.com/theQRL/go-zond/consensus/beacon" 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/core/vm" 31 "github.com/theQRL/go-zond/crypto/pqcrypto" 32 "github.com/theQRL/go-zond/params" 33 "github.com/theQRL/go-zond/trie" 34 ) 35 36 // Test chain parameters. 37 var ( 38 testKey, _ = pqcrypto.HexToDilithium("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 39 testAddress = testKey.GetAddress() 40 testDB = rawdb.NewMemoryDatabase() 41 42 testGspec = &core.Genesis{ 43 Config: params.TestChainConfig, 44 Alloc: core.GenesisAlloc{testAddress: {Balance: big.NewInt(1000000000000000)}}, 45 BaseFee: big.NewInt(params.InitialBaseFee), 46 } 47 testGenesis = testGspec.MustCommit(testDB, trie.NewDatabase(testDB, trie.HashDefaults)) 48 ) 49 50 // The common prefix of all test chains: 51 var testChainBase *testChain 52 53 var pregenerated bool 54 55 func init() { 56 // Reduce some of the parameters to make the tester faster 57 blockCacheMaxItems = 1024 58 fsHeaderSafetyNet = 256 59 fsHeaderContCheck = 500 * time.Millisecond 60 61 testChainBase = newTestChain(blockCacheMaxItems+200, testGenesis) 62 63 // Generate the test peers used by the tests to avoid overloading during testing. 64 // These seemingly random chains are used in various downloader tests. We're just 65 // pre-generating them here. 66 chains := []*testChain{ 67 testChainBase, 68 testChainBase.shorten(1), 69 testChainBase.shorten(blockCacheMaxItems - 15), 70 testChainBase.shorten((blockCacheMaxItems - 15) / 2), 71 testChainBase.shorten(blockCacheMaxItems - 15 - 5), 72 testChainBase.shorten(MaxHeaderFetch), 73 testChainBase.shorten(800), 74 testChainBase.shorten(800 / 2), 75 testChainBase.shorten(800 / 3), 76 testChainBase.shorten(800 / 4), 77 testChainBase.shorten(800 / 5), 78 testChainBase.shorten(800 / 6), 79 testChainBase.shorten(800 / 7), 80 testChainBase.shorten(800 / 8), 81 testChainBase.shorten(3*fsHeaderSafetyNet + 256 + fsMinFullBlocks), 82 testChainBase.shorten(fsMinFullBlocks + 256 - 1), 83 } 84 var wg sync.WaitGroup 85 wg.Add(len(chains)) 86 for _, chain := range chains { 87 go func(blocks []*types.Block) { 88 newTestBlockchain(blocks) 89 wg.Done() 90 }(chain.blocks[1:]) 91 } 92 wg.Wait() 93 94 // Mark the chains pregenerated. Generating a new one will lead to a panic. 95 pregenerated = true 96 } 97 98 type testChain struct { 99 blocks []*types.Block 100 } 101 102 // newTestChain creates a blockchain of the given length. 103 func newTestChain(length int, genesis *types.Block) *testChain { 104 tc := &testChain{ 105 blocks: []*types.Block{genesis}, 106 } 107 tc.generate(length-1, 0, genesis) 108 return tc 109 } 110 111 // shorten creates a copy of the chain with the given length. It panics if the 112 // length is longer than the number of available blocks. 113 func (tc *testChain) shorten(length int) *testChain { 114 if length > len(tc.blocks) { 115 panic(fmt.Errorf("can't shorten test chain to %d blocks, it's only %d blocks long", length, len(tc.blocks))) 116 } 117 return tc.copy(length) 118 } 119 120 func (tc *testChain) copy(newlen int) *testChain { 121 if newlen > len(tc.blocks) { 122 newlen = len(tc.blocks) 123 } 124 cpy := &testChain{ 125 blocks: append([]*types.Block{}, tc.blocks[:newlen]...), 126 } 127 return cpy 128 } 129 130 // generate creates a chain of n blocks starting at and including parent. 131 // the returned hash chain is ordered head->parent. In addition, every 22th block 132 // contains a transaction and every 5th an uncle to allow testing correct block 133 // reassembly. 134 func (tc *testChain) generate(n int, seed byte, parent *types.Block) { 135 blocks, _ := core.GenerateChain(testGspec.Config, parent, beacon.NewFaker(), testDB, n, func(i int, block *core.BlockGen) { 136 block.SetCoinbase(common.Address{seed}) 137 // Include transactions to the miner to make blocks more interesting. 138 if parent == tc.blocks[0] && i%22 == 0 { 139 signer := types.MakeSigner(params.TestChainConfig) 140 141 tx, err := types.SignTx(types.NewTx(&types.DynamicFeeTx{Nonce: block.TxNonce(testAddress), To: &common.Address{seed}, Value: big.NewInt(1000), Gas: params.TxGas, GasFeeCap: block.BaseFee(), Data: nil}), signer, testKey) 142 if err != nil { 143 panic(err) 144 } 145 block.AddTx(tx) 146 } 147 }) 148 tc.blocks = append(tc.blocks, blocks...) 149 } 150 151 var ( 152 testBlockchains = make(map[common.Hash]*testBlockchain) 153 testBlockchainsLock sync.Mutex 154 ) 155 156 type testBlockchain struct { 157 chain *core.BlockChain 158 gen sync.Once 159 } 160 161 // newTestBlockchain creates a blockchain database built by running the given blocks, 162 // either actually running them, or reusing a previously created one. The returned 163 // chains are *shared*, so *do not* mutate them. 164 func newTestBlockchain(blocks []*types.Block) *core.BlockChain { 165 // Retrieve an existing database, or create a new one 166 head := testGenesis.Hash() 167 if len(blocks) > 0 { 168 head = blocks[len(blocks)-1].Hash() 169 } 170 testBlockchainsLock.Lock() 171 if _, ok := testBlockchains[head]; !ok { 172 testBlockchains[head] = new(testBlockchain) 173 } 174 tbc := testBlockchains[head] 175 testBlockchainsLock.Unlock() 176 177 // Ensure that the database is generated 178 tbc.gen.Do(func() { 179 if pregenerated { 180 panic("Requested chain generation outside of init") 181 } 182 chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), nil, testGspec, beacon.NewFaker(), vm.Config{}, nil) 183 if err != nil { 184 panic(err) 185 } 186 if n, err := chain.InsertChain(blocks); err != nil { 187 panic(fmt.Sprintf("block %d: %v", n, err)) 188 } 189 tbc.chain = chain 190 }) 191 return tbc.chain 192 }