github.com/bcnmy/go-ethereum@v1.10.27/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 "encoding/json" 21 "math/big" 22 "runtime" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/consensus" 28 "github.com/ethereum/go-ethereum/consensus/beacon" 29 "github.com/ethereum/go-ethereum/consensus/clique" 30 "github.com/ethereum/go-ethereum/consensus/ethash" 31 "github.com/ethereum/go-ethereum/core/rawdb" 32 "github.com/ethereum/go-ethereum/core/types" 33 "github.com/ethereum/go-ethereum/core/vm" 34 "github.com/ethereum/go-ethereum/crypto" 35 "github.com/ethereum/go-ethereum/params" 36 ) 37 38 // Tests that simple header verification works, for both good and bad blocks. 39 func TestHeaderVerification(t *testing.T) { 40 // Create a simple chain to verify 41 var ( 42 testdb = rawdb.NewMemoryDatabase() 43 gspec = &Genesis{Config: params.TestChainConfig} 44 genesis = gspec.MustCommit(testdb) 45 blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 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 chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) 53 defer chain.Stop() 54 55 for i := 0; i < len(blocks); i++ { 56 for j, valid := range []bool{true, false} { 57 var results <-chan error 58 59 if valid { 60 engine := ethash.NewFaker() 61 _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) 62 } else { 63 engine := ethash.NewFakeFailer(headers[i].Number.Uint64()) 64 _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) 65 } 66 // Wait for the verification result 67 select { 68 case result := <-results: 69 if (result == nil) != valid { 70 t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, result, valid) 71 } 72 case <-time.After(time.Second): 73 t.Fatalf("test %d.%d: verification timeout", i, j) 74 } 75 // Make sure no more data is returned 76 select { 77 case result := <-results: 78 t.Fatalf("test %d.%d: unexpected result returned: %v", i, j, result) 79 case <-time.After(25 * time.Millisecond): 80 } 81 } 82 chain.InsertChain(blocks[i : i+1]) 83 } 84 } 85 86 func TestHeaderVerificationForMergingClique(t *testing.T) { testHeaderVerificationForMerging(t, true) } 87 func TestHeaderVerificationForMergingEthash(t *testing.T) { testHeaderVerificationForMerging(t, false) } 88 89 // Tests the verification for eth1/2 merging, including pre-merge and post-merge 90 func testHeaderVerificationForMerging(t *testing.T, isClique bool) { 91 var ( 92 testdb = rawdb.NewMemoryDatabase() 93 preBlocks []*types.Block 94 postBlocks []*types.Block 95 runEngine consensus.Engine 96 chainConfig *params.ChainConfig 97 merger = consensus.NewMerger(rawdb.NewMemoryDatabase()) 98 ) 99 if isClique { 100 var ( 101 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 102 addr = crypto.PubkeyToAddress(key.PublicKey) 103 engine = clique.New(params.AllCliqueProtocolChanges.Clique, testdb) 104 ) 105 genspec := &Genesis{ 106 ExtraData: make([]byte, 32+common.AddressLength+crypto.SignatureLength), 107 Alloc: map[common.Address]GenesisAccount{ 108 addr: {Balance: big.NewInt(1)}, 109 }, 110 BaseFee: big.NewInt(params.InitialBaseFee), 111 Difficulty: new(big.Int), 112 } 113 copy(genspec.ExtraData[32:], addr[:]) 114 genesis := genspec.MustCommit(testdb) 115 116 genEngine := beacon.New(engine) 117 preBlocks, _ = GenerateChain(params.AllCliqueProtocolChanges, genesis, genEngine, testdb, 8, nil) 118 td := 0 119 for i, block := range preBlocks { 120 header := block.Header() 121 if i > 0 { 122 header.ParentHash = preBlocks[i-1].Hash() 123 } 124 header.Extra = make([]byte, 32+crypto.SignatureLength) 125 header.Difficulty = big.NewInt(2) 126 127 sig, _ := crypto.Sign(genEngine.SealHash(header).Bytes(), key) 128 copy(header.Extra[len(header.Extra)-crypto.SignatureLength:], sig) 129 preBlocks[i] = block.WithSeal(header) 130 // calculate td 131 td += int(block.Difficulty().Uint64()) 132 } 133 config := *params.AllCliqueProtocolChanges 134 config.TerminalTotalDifficulty = big.NewInt(int64(td)) 135 postBlocks, _ = GenerateChain(&config, preBlocks[len(preBlocks)-1], genEngine, testdb, 8, nil) 136 chainConfig = &config 137 runEngine = beacon.New(engine) 138 } else { 139 gspec := &Genesis{Config: params.TestChainConfig} 140 genesis := gspec.MustCommit(testdb) 141 genEngine := beacon.New(ethash.NewFaker()) 142 143 preBlocks, _ = GenerateChain(params.TestChainConfig, genesis, genEngine, testdb, 8, nil) 144 td := 0 145 for _, block := range preBlocks { 146 // calculate td 147 td += int(block.Difficulty().Uint64()) 148 } 149 config := *params.TestChainConfig 150 config.TerminalTotalDifficulty = big.NewInt(int64(td)) 151 postBlocks, _ = GenerateChain(params.TestChainConfig, preBlocks[len(preBlocks)-1], genEngine, testdb, 8, nil) 152 153 chainConfig = &config 154 runEngine = beacon.New(ethash.NewFaker()) 155 } 156 157 preHeaders := make([]*types.Header, len(preBlocks)) 158 for i, block := range preBlocks { 159 preHeaders[i] = block.Header() 160 161 blob, _ := json.Marshal(block.Header()) 162 t.Logf("Log header before the merging %d: %v", block.NumberU64(), string(blob)) 163 } 164 postHeaders := make([]*types.Header, len(postBlocks)) 165 for i, block := range postBlocks { 166 postHeaders[i] = block.Header() 167 168 blob, _ := json.Marshal(block.Header()) 169 t.Logf("Log header after the merging %d: %v", block.NumberU64(), string(blob)) 170 } 171 // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces 172 chain, _ := NewBlockChain(testdb, nil, chainConfig, runEngine, vm.Config{}, nil, nil) 173 defer chain.Stop() 174 175 // Verify the blocks before the merging 176 for i := 0; i < len(preBlocks); i++ { 177 _, results := runEngine.VerifyHeaders(chain, []*types.Header{preHeaders[i]}, []bool{true}) 178 // Wait for the verification result 179 select { 180 case result := <-results: 181 if result != nil { 182 t.Errorf("test %d: verification failed %v", i, result) 183 } 184 case <-time.After(time.Second): 185 t.Fatalf("test %d: verification timeout", i) 186 } 187 // Make sure no more data is returned 188 select { 189 case result := <-results: 190 t.Fatalf("test %d: unexpected result returned: %v", i, result) 191 case <-time.After(25 * time.Millisecond): 192 } 193 chain.InsertChain(preBlocks[i : i+1]) 194 } 195 196 // Make the transition 197 merger.ReachTTD() 198 merger.FinalizePoS() 199 200 // Verify the blocks after the merging 201 for i := 0; i < len(postBlocks); i++ { 202 _, results := runEngine.VerifyHeaders(chain, []*types.Header{postHeaders[i]}, []bool{true}) 203 // Wait for the verification result 204 select { 205 case result := <-results: 206 if result != nil { 207 t.Errorf("test %d: verification failed %v", i, result) 208 } 209 case <-time.After(time.Second): 210 t.Fatalf("test %d: verification timeout", i) 211 } 212 // Make sure no more data is returned 213 select { 214 case result := <-results: 215 t.Fatalf("test %d: unexpected result returned: %v", i, result) 216 case <-time.After(25 * time.Millisecond): 217 } 218 chain.InsertBlockWithoutSetHead(postBlocks[i]) 219 } 220 221 // Verify the blocks with pre-merge blocks and post-merge blocks 222 var ( 223 headers []*types.Header 224 seals []bool 225 ) 226 for _, block := range preBlocks { 227 headers = append(headers, block.Header()) 228 seals = append(seals, true) 229 } 230 for _, block := range postBlocks { 231 headers = append(headers, block.Header()) 232 seals = append(seals, true) 233 } 234 _, results := runEngine.VerifyHeaders(chain, headers, seals) 235 for i := 0; i < len(headers); i++ { 236 select { 237 case result := <-results: 238 if result != nil { 239 t.Errorf("test %d: verification failed %v", i, result) 240 } 241 case <-time.After(time.Second): 242 t.Fatalf("test %d: verification timeout", i) 243 } 244 } 245 // Make sure no more data is returned 246 select { 247 case result := <-results: 248 t.Fatalf("unexpected result returned: %v", result) 249 case <-time.After(25 * time.Millisecond): 250 } 251 } 252 253 // Tests that concurrent header verification works, for both good and bad blocks. 254 func TestHeaderConcurrentVerification2(t *testing.T) { testHeaderConcurrentVerification(t, 2) } 255 func TestHeaderConcurrentVerification8(t *testing.T) { testHeaderConcurrentVerification(t, 8) } 256 func TestHeaderConcurrentVerification32(t *testing.T) { testHeaderConcurrentVerification(t, 32) } 257 258 func testHeaderConcurrentVerification(t *testing.T, threads int) { 259 // Create a simple chain to verify 260 var ( 261 testdb = rawdb.NewMemoryDatabase() 262 gspec = &Genesis{Config: params.TestChainConfig} 263 genesis = gspec.MustCommit(testdb) 264 blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil) 265 ) 266 headers := make([]*types.Header, len(blocks)) 267 seals := make([]bool, len(blocks)) 268 269 for i, block := range blocks { 270 headers[i] = block.Header() 271 seals[i] = true 272 } 273 // Set the number of threads to verify on 274 old := runtime.GOMAXPROCS(threads) 275 defer runtime.GOMAXPROCS(old) 276 277 // Run the header checker for the entire block chain at once both for a valid and 278 // also an invalid chain (enough if one arbitrary block is invalid). 279 for i, valid := range []bool{true, false} { 280 var results <-chan error 281 282 if valid { 283 chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) 284 _, results = chain.engine.VerifyHeaders(chain, headers, seals) 285 chain.Stop() 286 } else { 287 chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) 288 _, results = chain.engine.VerifyHeaders(chain, headers, seals) 289 chain.Stop() 290 } 291 // Wait for all the verification results 292 checks := make(map[int]error) 293 for j := 0; j < len(blocks); j++ { 294 select { 295 case result := <-results: 296 checks[j] = result 297 298 case <-time.After(time.Second): 299 t.Fatalf("test %d.%d: verification timeout", i, j) 300 } 301 } 302 // Check nonce check validity 303 for j := 0; j < len(blocks); j++ { 304 want := valid || (j < len(blocks)-2) // We chose the last-but-one nonce in the chain to fail 305 if (checks[j] == nil) != want { 306 t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, checks[j], want) 307 } 308 if !want { 309 // A few blocks after the first error may pass verification due to concurrent 310 // workers. We don't care about those in this test, just that the correct block 311 // errors out. 312 break 313 } 314 } 315 // Make sure no more data is returned 316 select { 317 case result := <-results: 318 t.Fatalf("test %d: unexpected result returned: %v", i, result) 319 case <-time.After(25 * time.Millisecond): 320 } 321 } 322 } 323 324 // Tests that aborting a header validation indeed prevents further checks from being 325 // run, as well as checks that no left-over goroutines are leaked. 326 func TestHeaderConcurrentAbortion2(t *testing.T) { testHeaderConcurrentAbortion(t, 2) } 327 func TestHeaderConcurrentAbortion8(t *testing.T) { testHeaderConcurrentAbortion(t, 8) } 328 func TestHeaderConcurrentAbortion32(t *testing.T) { testHeaderConcurrentAbortion(t, 32) } 329 330 func testHeaderConcurrentAbortion(t *testing.T, threads int) { 331 // Create a simple chain to verify 332 var ( 333 testdb = rawdb.NewMemoryDatabase() 334 gspec = &Genesis{Config: params.TestChainConfig} 335 genesis = gspec.MustCommit(testdb) 336 blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil) 337 ) 338 headers := make([]*types.Header, len(blocks)) 339 seals := make([]bool, len(blocks)) 340 341 for i, block := range blocks { 342 headers[i] = block.Header() 343 seals[i] = true 344 } 345 // Set the number of threads to verify on 346 old := runtime.GOMAXPROCS(threads) 347 defer runtime.GOMAXPROCS(old) 348 349 // Start the verifications and immediately abort 350 chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) 351 defer chain.Stop() 352 353 abort, results := chain.engine.VerifyHeaders(chain, headers, seals) 354 close(abort) 355 356 // Deplete the results channel 357 verified := 0 358 for depleted := false; !depleted; { 359 select { 360 case result := <-results: 361 if result != nil { 362 t.Errorf("header %d: validation failed: %v", verified, result) 363 } 364 verified++ 365 case <-time.After(50 * time.Millisecond): 366 depleted = true 367 } 368 } 369 // Check that abortion was honored by not processing too many POWs 370 if verified > 2*threads { 371 t.Errorf("verification count too large: have %d, want below %d", verified, 2*threads) 372 } 373 } 374 375 func TestCalcGasLimit(t *testing.T) { 376 for i, tc := range []struct { 377 pGasLimit uint64 378 max uint64 379 min uint64 380 }{ 381 {20000000, 20019530, 19980470}, 382 {40000000, 40039061, 39960939}, 383 } { 384 // Increase 385 if have, want := CalcGasLimit(tc.pGasLimit, 2*tc.pGasLimit), tc.max; have != want { 386 t.Errorf("test %d: have %d want <%d", i, have, want) 387 } 388 // Decrease 389 if have, want := CalcGasLimit(tc.pGasLimit, 0), tc.min; have != want { 390 t.Errorf("test %d: have %d want >%d", i, have, want) 391 } 392 // Small decrease 393 if have, want := CalcGasLimit(tc.pGasLimit, tc.pGasLimit-1), tc.pGasLimit-1; have != want { 394 t.Errorf("test %d: have %d want %d", i, have, want) 395 } 396 // Small increase 397 if have, want := CalcGasLimit(tc.pGasLimit, tc.pGasLimit+1), tc.pGasLimit+1; have != want { 398 t.Errorf("test %d: have %d want %d", i, have, want) 399 } 400 // No change 401 if have, want := CalcGasLimit(tc.pGasLimit, tc.pGasLimit), tc.pGasLimit; have != want { 402 t.Errorf("test %d: have %d want %d", i, have, want) 403 } 404 } 405 }