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  }