github.com/ethereum/go-ethereum@v1.16.1/core/block_validator_test.go (about) 1 // Copyright 2015 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 core 18 19 import ( 20 "math/big" 21 "testing" 22 "time" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/consensus" 26 "github.com/ethereum/go-ethereum/consensus/beacon" 27 "github.com/ethereum/go-ethereum/consensus/clique" 28 "github.com/ethereum/go-ethereum/consensus/ethash" 29 "github.com/ethereum/go-ethereum/core/rawdb" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/params" 33 ) 34 35 // Tests that simple header verification works, for both good and bad blocks. 36 func TestHeaderVerification(t *testing.T) { 37 testHeaderVerification(t, rawdb.HashScheme) 38 testHeaderVerification(t, rawdb.PathScheme) 39 } 40 41 func testHeaderVerification(t *testing.T, scheme string) { 42 // Create a simple chain to verify 43 var ( 44 gspec = &Genesis{Config: params.TestChainConfig} 45 _, blocks, _ = GenerateChainWithGenesis(gspec, ethash.NewFaker(), 8, nil) 46 ) 47 headers := make([]*types.Header, len(blocks)) 48 for i, block := range blocks { 49 headers[i] = block.Header() 50 } 51 // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces 52 options := DefaultConfig().WithStateScheme(scheme) 53 chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, ethash.NewFaker(), options) 54 defer chain.Stop() 55 if err != nil { 56 t.Fatal(err) 57 } 58 59 for i := 0; i < len(blocks); i++ { 60 for j, valid := range []bool{true, false} { 61 var results <-chan error 62 63 if valid { 64 engine := ethash.NewFaker() 65 _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}) 66 } else { 67 engine := ethash.NewFakeFailer(headers[i].Number.Uint64()) 68 _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}) 69 } 70 // Wait for the verification result 71 select { 72 case result := <-results: 73 if (result == nil) != valid { 74 t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, result, valid) 75 } 76 case <-time.After(time.Second): 77 t.Fatalf("test %d.%d: verification timeout", i, j) 78 } 79 // Make sure no more data is returned 80 select { 81 case result := <-results: 82 t.Fatalf("test %d.%d: unexpected result returned: %v", i, j, result) 83 case <-time.After(25 * time.Millisecond): 84 } 85 } 86 chain.InsertChain(blocks[i : i+1]) 87 } 88 } 89 90 func TestHeaderVerificationForMergingClique(t *testing.T) { testHeaderVerificationForMerging(t, true) } 91 func TestHeaderVerificationForMergingEthash(t *testing.T) { testHeaderVerificationForMerging(t, false) } 92 93 // Tests the verification for eth1/2 merging, including pre-merge and post-merge 94 func testHeaderVerificationForMerging(t *testing.T, isClique bool) { 95 var ( 96 gspec *Genesis 97 preBlocks []*types.Block 98 postBlocks []*types.Block 99 engine consensus.Engine 100 ) 101 if isClique { 102 var ( 103 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 104 addr = crypto.PubkeyToAddress(key.PublicKey) 105 config = *params.AllCliqueProtocolChanges 106 ) 107 engine = beacon.New(clique.New(params.AllCliqueProtocolChanges.Clique, rawdb.NewMemoryDatabase())) 108 gspec = &Genesis{ 109 Config: &config, 110 ExtraData: make([]byte, 32+common.AddressLength+crypto.SignatureLength), 111 Alloc: map[common.Address]types.Account{ 112 addr: {Balance: big.NewInt(1)}, 113 }, 114 BaseFee: big.NewInt(params.InitialBaseFee), 115 Difficulty: new(big.Int), 116 } 117 copy(gspec.ExtraData[32:], addr[:]) 118 119 // chain_maker has no blockchain to retrieve the TTD from, setting to nil 120 // is a hack to signal it to generate pre-merge blocks 121 gspec.Config.TerminalTotalDifficulty = nil 122 td := 0 123 genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil) 124 125 for i, block := range blocks { 126 header := block.Header() 127 if i > 0 { 128 header.ParentHash = blocks[i-1].Hash() 129 } 130 header.Extra = make([]byte, 32+crypto.SignatureLength) 131 header.Difficulty = big.NewInt(2) 132 133 sig, _ := crypto.Sign(engine.SealHash(header).Bytes(), key) 134 copy(header.Extra[len(header.Extra)-crypto.SignatureLength:], sig) 135 blocks[i] = block.WithSeal(header) 136 137 // calculate td 138 td += int(block.Difficulty().Uint64()) 139 } 140 preBlocks = blocks 141 gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td)) 142 postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, nil) 143 } else { 144 config := *params.TestChainConfig 145 gspec = &Genesis{Config: &config} 146 engine = beacon.New(ethash.NewFaker()) 147 td := int(params.GenesisDifficulty.Uint64()) 148 genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil) 149 for _, block := range blocks { 150 // calculate td 151 td += int(block.Difficulty().Uint64()) 152 } 153 preBlocks = blocks 154 gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td)) 155 postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, func(i int, gen *BlockGen) { 156 gen.SetPoS() 157 }) 158 } 159 // Assemble header batch 160 preHeaders := make([]*types.Header, len(preBlocks)) 161 for i, block := range preBlocks { 162 preHeaders[i] = block.Header() 163 } 164 postHeaders := make([]*types.Header, len(postBlocks)) 165 for i, block := range postBlocks { 166 postHeaders[i] = block.Header() 167 } 168 // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces 169 chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), gspec, engine, nil) 170 defer chain.Stop() 171 if err != nil { 172 t.Fatal(err) 173 } 174 175 // Verify the blocks before the merging 176 for i := 0; i < len(preBlocks); i++ { 177 _, results := engine.VerifyHeaders(chain, []*types.Header{preHeaders[i]}) 178 // Wait for the verification result 179 select { 180 case result := <-results: 181 if result != nil { 182 t.Errorf("pre-block %d: verification failed %v", i, result) 183 } 184 case <-time.After(time.Second): 185 t.Fatalf("pre-block %d: verification timeout", i) 186 } 187 // Make sure no more data is returned 188 select { 189 case result := <-results: 190 t.Fatalf("pre-block %d: unexpected result returned: %v", i, result) 191 case <-time.After(25 * time.Millisecond): 192 } 193 chain.InsertChain(preBlocks[i : i+1]) 194 } 195 // Verify the blocks after the merging 196 for i := 0; i < len(postBlocks); i++ { 197 _, results := engine.VerifyHeaders(chain, []*types.Header{postHeaders[i]}) 198 // Wait for the verification result 199 select { 200 case result := <-results: 201 if result != nil { 202 t.Errorf("post-block %d: verification failed %v", i, result) 203 } 204 case <-time.After(time.Second): 205 t.Fatalf("test %d: verification timeout", i) 206 } 207 // Make sure no more data is returned 208 select { 209 case result := <-results: 210 t.Fatalf("post-block %d: unexpected result returned: %v", i, result) 211 case <-time.After(25 * time.Millisecond): 212 } 213 chain.InsertBlockWithoutSetHead(postBlocks[i], false) 214 } 215 216 // Verify the blocks with pre-merge blocks and post-merge blocks 217 var headers []*types.Header 218 for _, block := range preBlocks { 219 headers = append(headers, block.Header()) 220 } 221 for _, block := range postBlocks { 222 headers = append(headers, block.Header()) 223 } 224 _, results := engine.VerifyHeaders(chain, headers) 225 for i := 0; i < len(headers); i++ { 226 select { 227 case result := <-results: 228 if result != nil { 229 t.Errorf("test %d: verification failed %v", i, result) 230 } 231 case <-time.After(time.Second): 232 t.Fatalf("test %d: verification timeout", i) 233 } 234 } 235 // Make sure no more data is returned 236 select { 237 case result := <-results: 238 t.Fatalf("unexpected result returned: %v", result) 239 case <-time.After(25 * time.Millisecond): 240 } 241 } 242 243 func TestCalcGasLimit(t *testing.T) { 244 for i, tc := range []struct { 245 pGasLimit uint64 246 max uint64 247 min uint64 248 }{ 249 {20000000, 20019530, 19980470}, 250 {40000000, 40039061, 39960939}, 251 } { 252 // Increase 253 if have, want := CalcGasLimit(tc.pGasLimit, 2*tc.pGasLimit), tc.max; have != want { 254 t.Errorf("test %d: have %d want <%d", i, have, want) 255 } 256 // Decrease 257 if have, want := CalcGasLimit(tc.pGasLimit, 0), tc.min; have != want { 258 t.Errorf("test %d: have %d want >%d", i, have, want) 259 } 260 // Small decrease 261 if have, want := CalcGasLimit(tc.pGasLimit, tc.pGasLimit-1), tc.pGasLimit-1; have != want { 262 t.Errorf("test %d: have %d want %d", i, have, want) 263 } 264 // Small increase 265 if have, want := CalcGasLimit(tc.pGasLimit, tc.pGasLimit+1), tc.pGasLimit+1; have != want { 266 t.Errorf("test %d: have %d want %d", i, have, want) 267 } 268 // No change 269 if have, want := CalcGasLimit(tc.pGasLimit, tc.pGasLimit), tc.pGasLimit; have != want { 270 t.Errorf("test %d: have %d want %d", i, have, want) 271 } 272 } 273 }