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