github.com/klaytn/klaytn@v1.12.1/datasync/downloader/testchain_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2018 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum 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-ethereum 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-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from eth/downloader/testchain_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package downloader 22 23 import ( 24 "fmt" 25 "math/big" 26 "sync" 27 28 "github.com/klaytn/klaytn/blockchain" 29 "github.com/klaytn/klaytn/blockchain/types" 30 "github.com/klaytn/klaytn/common" 31 "github.com/klaytn/klaytn/consensus/gxhash" 32 "github.com/klaytn/klaytn/crypto" 33 "github.com/klaytn/klaytn/params" 34 "github.com/klaytn/klaytn/storage/database" 35 ) 36 37 // Test chain parameters. 38 var ( 39 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 40 testAddress = crypto.PubkeyToAddress(testKey.PublicKey) 41 testDB = database.NewMemoryDBManager() 42 testGenesis = blockchain.GenesisBlockForTesting(testDB, testAddress, big.NewInt(1000000000)) 43 ) 44 45 // The common prefix of all test chains: 46 var testChainBase = newTestChain(blockCacheMaxItems+200, testGenesis) 47 48 // Different forks on top of the base chain: 49 var testChainForkLightA, testChainForkLightB, testChainForkHeavy *testChain 50 51 func init() { 52 forkLen := int(MaxForkAncestry + 50) 53 var wg sync.WaitGroup 54 wg.Add(3) 55 go func() { testChainForkLightA = testChainBase.makeFork(forkLen, false, 1); wg.Done() }() 56 go func() { testChainForkLightB = testChainBase.makeFork(forkLen, false, 2); wg.Done() }() 57 go func() { testChainForkHeavy = testChainBase.makeFork(forkLen, true, 3); wg.Done() }() 58 wg.Wait() 59 } 60 61 type testChain struct { 62 genesis *types.Block 63 chain []common.Hash 64 headerm map[common.Hash]*types.Header 65 blockm map[common.Hash]*types.Block 66 receiptm map[common.Hash][]*types.Receipt 67 tdm map[common.Hash]*big.Int 68 } 69 70 // newTestChain creates a blockchain of the given length. 71 func newTestChain(length int, genesis *types.Block) *testChain { 72 tc := new(testChain).copy(length) 73 tc.genesis = genesis 74 tc.chain = append(tc.chain, genesis.Hash()) 75 tc.headerm[tc.genesis.Hash()] = tc.genesis.Header() 76 tc.tdm[tc.genesis.Hash()] = tc.genesis.BlockScore() 77 tc.blockm[tc.genesis.Hash()] = tc.genesis 78 tc.generate(length-1, 0, genesis, false) 79 return tc 80 } 81 82 // makeFork creates a fork on top of the test chain. 83 func (tc *testChain) makeFork(length int, heavy bool, seed byte) *testChain { 84 fork := tc.copy(tc.len() + length) 85 fork.generate(length, seed, tc.headBlock(), heavy) 86 return fork 87 } 88 89 // shorten creates a copy of the chain with the given length. It panics if the 90 // length is longer than the number of available blocks. 91 func (tc *testChain) shorten(length int) *testChain { 92 if length > tc.len() { 93 panic(fmt.Errorf("can't shorten test chain to %d blocks, it's only %d blocks long", length, tc.len())) 94 } 95 return tc.copy(length) 96 } 97 98 func (tc *testChain) copy(newlen int) *testChain { 99 cpy := &testChain{ 100 genesis: tc.genesis, 101 headerm: make(map[common.Hash]*types.Header, newlen), 102 blockm: make(map[common.Hash]*types.Block, newlen), 103 receiptm: make(map[common.Hash][]*types.Receipt, newlen), 104 tdm: make(map[common.Hash]*big.Int, newlen), 105 } 106 for i := 0; i < len(tc.chain) && i < newlen; i++ { 107 hash := tc.chain[i] 108 cpy.chain = append(cpy.chain, tc.chain[i]) 109 cpy.tdm[hash] = tc.tdm[hash] 110 cpy.blockm[hash] = tc.blockm[hash] 111 cpy.headerm[hash] = tc.headerm[hash] 112 cpy.receiptm[hash] = tc.receiptm[hash] 113 } 114 return cpy 115 } 116 117 // generate creates a chain of n blocks starting at and including parent. 118 // the returned hash chain is ordered head->parent. In addition, every 22th block 119 // contains a transaction to allow testing correct block 120 // reassembly. 121 func (tc *testChain) generate(n int, seed byte, parent *types.Block, heavy bool) { 122 // start := time.Now() 123 // defer func() { fmt.Printf("test chain generated in %v\n", time.Since(start)) }() 124 125 blocks, receipts := blockchain.GenerateChain(params.TestChainConfig, parent, gxhash.NewFaker(), testDB, n, func(i int, block *blockchain.BlockGen) { 126 block.SetRewardbase(common.Address{seed}) 127 // If a heavy chain is requested, delay blocks to raise blockscore 128 if heavy { 129 block.OffsetTime(-1) 130 } 131 // Include transactions to the miner to make blocks more interesting. 132 if parent == tc.genesis && i%22 == 0 { 133 signer := types.MakeSigner(params.TestChainConfig, block.Number()) 134 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) 135 if err != nil { 136 panic(err) 137 } 138 block.AddTx(tx) 139 } 140 }) 141 142 // Convert the block-chain into a hash-chain and header/block maps 143 td := new(big.Int).Set(tc.td(parent.Hash())) 144 for i, b := range blocks { 145 td := td.Add(td, b.BlockScore()) 146 hash := b.Hash() 147 tc.chain = append(tc.chain, hash) 148 tc.blockm[hash] = b 149 tc.headerm[hash] = b.Header() 150 tc.receiptm[hash] = receipts[i] 151 tc.tdm[hash] = new(big.Int).Set(td) 152 } 153 } 154 155 // len returns the total number of blocks in the chain. 156 func (tc *testChain) len() int { 157 return len(tc.chain) 158 } 159 160 // headBlock returns the head of the chain. 161 func (tc *testChain) headBlock() *types.Block { 162 return tc.blockm[tc.chain[len(tc.chain)-1]] 163 } 164 165 // td returns the total blockscore of the given block. 166 func (tc *testChain) td(hash common.Hash) *big.Int { 167 return tc.tdm[hash] 168 } 169 170 // headersByHash returns headers in ascending order from the given hash. 171 func (tc *testChain) headersByHash(origin common.Hash, amount int, skip int) []*types.Header { 172 num, _ := tc.hashToNumber(origin) 173 return tc.headersByNumber(num, amount, skip) 174 } 175 176 // headersByNumber returns headers in ascending order from the given number. 177 func (tc *testChain) headersByNumber(origin uint64, amount int, skip int) []*types.Header { 178 result := make([]*types.Header, 0, amount) 179 for num := origin; num < uint64(len(tc.chain)) && len(result) < amount; num += uint64(skip) + 1 { 180 if header, ok := tc.headerm[tc.chain[int(num)]]; ok { 181 result = append(result, header) 182 } 183 } 184 return result 185 } 186 187 // receipts returns the receipts of the given block hashes. 188 func (tc *testChain) receipts(hashes []common.Hash) [][]*types.Receipt { 189 results := make([][]*types.Receipt, 0, len(hashes)) 190 for _, hash := range hashes { 191 if receipt, ok := tc.receiptm[hash]; ok { 192 results = append(results, receipt) 193 } 194 } 195 return results 196 } 197 198 // bodies returns the block bodies of the given block hashes. 199 func (tc *testChain) bodies(hashes []common.Hash) [][]*types.Transaction { 200 transactions := make([][]*types.Transaction, 0, len(hashes)) 201 for _, hash := range hashes { 202 if block, ok := tc.blockm[hash]; ok { 203 transactions = append(transactions, block.Transactions()) 204 } 205 } 206 return transactions 207 } 208 209 func (tc *testChain) hashToNumber(target common.Hash) (uint64, bool) { 210 for num, hash := range tc.chain { 211 if hash == target { 212 return uint64(num), true 213 } 214 } 215 return 0, false 216 }