github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/eth/downloader/testchain_test.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package downloader 19 20 import ( 21 "fmt" 22 "math/big" 23 "sync" 24 25 "github.com/AigarNetwork/aigar/common" 26 "github.com/AigarNetwork/aigar/consensus/ethash" 27 "github.com/AigarNetwork/aigar/core" 28 "github.com/AigarNetwork/aigar/core/rawdb" 29 "github.com/AigarNetwork/aigar/core/types" 30 "github.com/AigarNetwork/aigar/crypto" 31 "github.com/AigarNetwork/aigar/params" 32 ) 33 34 // Test chain parameters. 35 var ( 36 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 37 testAddress = crypto.PubkeyToAddress(testKey.PublicKey) 38 testDB = rawdb.NewMemoryDatabase() 39 testGenesis = core.GenesisBlockForTesting(testDB, testAddress, big.NewInt(1000000000)) 40 ) 41 42 // The common prefix of all test chains: 43 var testChainBase = newTestChain(blockCacheItems+200, testGenesis) 44 45 // Different forks on top of the base chain: 46 var testChainForkLightA, testChainForkLightB, testChainForkHeavy *testChain 47 48 func init() { 49 var forkLen = int(maxForkAncestry + 50) 50 var wg sync.WaitGroup 51 wg.Add(3) 52 go func() { testChainForkLightA = testChainBase.makeFork(forkLen, false, 1); wg.Done() }() 53 go func() { testChainForkLightB = testChainBase.makeFork(forkLen, false, 2); wg.Done() }() 54 go func() { testChainForkHeavy = testChainBase.makeFork(forkLen, true, 3); wg.Done() }() 55 wg.Wait() 56 } 57 58 type testChain struct { 59 genesis *types.Block 60 chain []common.Hash 61 headerm map[common.Hash]*types.Header 62 blockm map[common.Hash]*types.Block 63 receiptm map[common.Hash][]*types.Receipt 64 tdm map[common.Hash]*big.Int 65 } 66 67 // newTestChain creates a blockchain of the given length. 68 func newTestChain(length int, genesis *types.Block) *testChain { 69 tc := new(testChain).copy(length) 70 tc.genesis = genesis 71 tc.chain = append(tc.chain, genesis.Hash()) 72 tc.headerm[tc.genesis.Hash()] = tc.genesis.Header() 73 tc.tdm[tc.genesis.Hash()] = tc.genesis.Difficulty() 74 tc.blockm[tc.genesis.Hash()] = tc.genesis 75 tc.generate(length-1, 0, genesis, false) 76 return tc 77 } 78 79 // makeFork creates a fork on top of the test chain. 80 func (tc *testChain) makeFork(length int, heavy bool, seed byte) *testChain { 81 fork := tc.copy(tc.len() + length) 82 fork.generate(length, seed, tc.headBlock(), heavy) 83 return fork 84 } 85 86 // shorten creates a copy of the chain with the given length. It panics if the 87 // length is longer than the number of available blocks. 88 func (tc *testChain) shorten(length int) *testChain { 89 if length > tc.len() { 90 panic(fmt.Errorf("can't shorten test chain to %d blocks, it's only %d blocks long", length, tc.len())) 91 } 92 return tc.copy(length) 93 } 94 95 func (tc *testChain) copy(newlen int) *testChain { 96 cpy := &testChain{ 97 genesis: tc.genesis, 98 headerm: make(map[common.Hash]*types.Header, newlen), 99 blockm: make(map[common.Hash]*types.Block, newlen), 100 receiptm: make(map[common.Hash][]*types.Receipt, newlen), 101 tdm: make(map[common.Hash]*big.Int, newlen), 102 } 103 for i := 0; i < len(tc.chain) && i < newlen; i++ { 104 hash := tc.chain[i] 105 cpy.chain = append(cpy.chain, tc.chain[i]) 106 cpy.tdm[hash] = tc.tdm[hash] 107 cpy.blockm[hash] = tc.blockm[hash] 108 cpy.headerm[hash] = tc.headerm[hash] 109 cpy.receiptm[hash] = tc.receiptm[hash] 110 } 111 return cpy 112 } 113 114 // generate creates a chain of n blocks starting at and including parent. 115 // the returned hash chain is ordered head->parent. In addition, every 22th block 116 // contains a transaction and every 5th an uncle to allow testing correct block 117 // reassembly. 118 func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool) { 119 // start := time.Now() 120 // defer func() { fmt.Printf("test chain generated in %v\n", time.Since(start)) }() 121 122 blocks, receipts := core.GenerateChain(params.TestChainConfig, parent, ethash.NewFaker(), testDB, n, func(i int, block *core.BlockGen) { 123 block.SetCoinbase(common.Address{seed}) 124 // If a heavy chain is requested, delay blocks to raise difficulty 125 if heavy { 126 block.OffsetTime(-1) 127 } 128 // Include transactions to the miner to make blocks more interesting. 129 if parent == tc.genesis && i%22 == 0 { 130 signer := types.MakeSigner(params.TestChainConfig, block.Number()) 131 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) 132 if err != nil { 133 panic(err) 134 } 135 block.AddTx(tx) 136 } 137 // if the block number is a multiple of 5, add a bonus uncle to the block 138 if i > 0 && i%5 == 0 { 139 block.AddUncle(&types.Header{ 140 ParentHash: block.PrevBlock(i - 1).Hash(), 141 Number: big.NewInt(block.Number().Int64() - 1), 142 }) 143 } 144 }) 145 146 // Convert the block-chain into a hash-chain and header/block maps 147 td := new(big.Int).Set(tc.td(parent.Hash())) 148 for i, b := range blocks { 149 td := td.Add(td, b.Difficulty()) 150 hash := b.Hash() 151 tc.chain = append(tc.chain, hash) 152 tc.blockm[hash] = b 153 tc.headerm[hash] = b.Header() 154 tc.receiptm[hash] = receipts[i] 155 tc.tdm[hash] = new(big.Int).Set(td) 156 } 157 } 158 159 // len returns the total number of blocks in the chain. 160 func (tc *testChain) len() int { 161 return len(tc.chain) 162 } 163 164 // headBlock returns the head of the chain. 165 func (tc *testChain) headBlock() *types.Block { 166 return tc.blockm[tc.chain[len(tc.chain)-1]] 167 } 168 169 // td returns the total difficulty of the given block. 170 func (tc *testChain) td(hash common.Hash) *big.Int { 171 return tc.tdm[hash] 172 } 173 174 // headersByHash returns headers in ascending order from the given hash. 175 func (tc *testChain) headersByHash(origin common.Hash, amount int, skip int) []*types.Header { 176 num, _ := tc.hashToNumber(origin) 177 return tc.headersByNumber(num, amount, skip) 178 } 179 180 // headersByNumber returns headers in ascending order from the given number. 181 func (tc *testChain) headersByNumber(origin uint64, amount int, skip int) []*types.Header { 182 result := make([]*types.Header, 0, amount) 183 for num := origin; num < uint64(len(tc.chain)) && len(result) < amount; num += uint64(skip) + 1 { 184 if header, ok := tc.headerm[tc.chain[int(num)]]; ok { 185 result = append(result, header) 186 } 187 } 188 return result 189 } 190 191 // receipts returns the receipts of the given block hashes. 192 func (tc *testChain) receipts(hashes []common.Hash) [][]*types.Receipt { 193 results := make([][]*types.Receipt, 0, len(hashes)) 194 for _, hash := range hashes { 195 if receipt, ok := tc.receiptm[hash]; ok { 196 results = append(results, receipt) 197 } 198 } 199 return results 200 } 201 202 // bodies returns the block bodies of the given block hashes. 203 func (tc *testChain) bodies(hashes []common.Hash) ([][]*types.Transaction, [][]*types.Header) { 204 transactions := make([][]*types.Transaction, 0, len(hashes)) 205 uncles := make([][]*types.Header, 0, len(hashes)) 206 for _, hash := range hashes { 207 if block, ok := tc.blockm[hash]; ok { 208 transactions = append(transactions, block.Transactions()) 209 uncles = append(uncles, block.Uncles()) 210 } 211 } 212 return transactions, uncles 213 } 214 215 func (tc *testChain) hashToNumber(target common.Hash) (uint64, bool) { 216 for num, hash := range tc.chain { 217 if hash == target { 218 return uint64(num), true 219 } 220 } 221 return 0, false 222 }