github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/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 "runtime" 21 "testing" 22 "time" 23 24 "github.com/wanchain/go-wanchain/consensus/ethash" 25 "github.com/wanchain/go-wanchain/core/types" 26 "github.com/wanchain/go-wanchain/core/vm" 27 "github.com/wanchain/go-wanchain/ethdb" 28 "github.com/wanchain/go-wanchain/params" 29 ) 30 31 // Tests that simple header verification works, for both good and bad blocks. 32 func TestHeaderVerification(t *testing.T) { 33 // Create a simple chain to verify 34 var ( 35 testdb, _ = ethdb.NewMemDatabase() 36 gspec = DefaultPPOWTestingGenesisBlock() 37 genesis = gspec.MustCommit(testdb) 38 ) 39 40 chainEngine := ethash.NewFaker(testdb) 41 // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces 42 chain, _ := NewBlockChain(testdb, params.TestChainConfig, chainEngine, vm.Config{}) 43 defer chain.Stop() 44 chainEnv := NewChainEnv(params.TestChainConfig, gspec, chainEngine, chain, testdb) 45 blocks, _ := chainEnv.GenerateChain(genesis, 8, nil) 46 47 headers := make([]*types.Header, len(blocks)) 48 for i, block := range blocks { 49 headers[i] = block.Header() 50 } 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(testdb) 58 _, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true}) 59 } else { 60 engine := ethash.NewFakeFailer(headers[i].Number.Uint64(), testdb) 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 // Tests that concurrent header verification works, for both good and bad blocks. 84 func TestHeaderConcurrentVerification2(t *testing.T) { testHeaderConcurrentVerification(t, 2) } 85 func TestHeaderConcurrentVerification8(t *testing.T) { testHeaderConcurrentVerification(t, 8) } 86 func TestHeaderConcurrentVerification32(t *testing.T) { testHeaderConcurrentVerification(t, 32) } 87 88 func testHeaderConcurrentVerification(t *testing.T, threads int) { 89 // Create a simple chain to verify 90 var ( 91 testdb, _ = ethdb.NewMemDatabase() 92 gspec = DefaultPPOWTestingGenesisBlock() 93 genesis = gspec.MustCommit(testdb) 94 //blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil) 95 ) 96 97 chainEngine := ethash.NewFaker(testdb) 98 // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces 99 chain, _ := NewBlockChain(testdb, params.TestChainConfig, chainEngine, vm.Config{}) 100 defer chain.Stop() 101 chainEnv := NewChainEnv(params.TestChainConfig, gspec, chainEngine, chain, testdb) 102 blocks, _ := chainEnv.GenerateChain(genesis, 8, nil) 103 104 headers := make([]*types.Header, len(blocks)) 105 seals := make([]bool, len(blocks)) 106 107 for i, block := range blocks { 108 headers[i] = block.Header() 109 seals[i] = true 110 } 111 // Set the number of threads to verify on 112 old := runtime.GOMAXPROCS(threads) 113 defer runtime.GOMAXPROCS(old) 114 115 // Run the header checker for the entire block chain at once both for a valid and 116 // also an invalid chain (enough if one arbitrary block is invalid). 117 for i, valid := range []bool{true, false} { 118 var results <-chan error 119 120 if valid { 121 chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFaker(testdb), vm.Config{}) 122 _, results = chain.engine.VerifyHeaders(chain, headers, seals) 123 chain.Stop() 124 } else { 125 chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1), testdb), vm.Config{}) 126 _, results = chain.engine.VerifyHeaders(chain, headers, seals) 127 chain.Stop() 128 } 129 // Wait for all the verification results 130 checks := make(map[int]error) 131 for j := 0; j < len(blocks); j++ { 132 select { 133 case result := <-results: 134 checks[j] = result 135 136 case <-time.After(time.Second): 137 t.Fatalf("test %d.%d: verification timeout", i, j) 138 } 139 } 140 // Check nonce check validity 141 for j := 0; j < len(blocks); j++ { 142 want := valid || (j < len(blocks)-2) // We chose the last-but-one nonce in the chain to fail 143 if (checks[j] == nil) != want { 144 t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, checks[j], want) 145 } 146 if !want { 147 // A few blocks after the first error may pass verification due to concurrent 148 // workers. We don't care about those in this test, just that the correct block 149 // errors out. 150 break 151 } 152 } 153 // Make sure no more data is returned 154 select { 155 case result := <-results: 156 t.Fatalf("test %d: unexpected result returned: %v", i, result) 157 case <-time.After(25 * time.Millisecond): 158 } 159 } 160 } 161 162 // Tests that aborting a header validation indeed prevents further checks from being 163 // run, as well as checks that no left-over goroutines are leaked. 164 func TestHeaderConcurrentAbortion2(t *testing.T) { testHeaderConcurrentAbortion(t, 2) } 165 func TestHeaderConcurrentAbortion8(t *testing.T) { testHeaderConcurrentAbortion(t, 8) } 166 func TestHeaderConcurrentAbortion32(t *testing.T) { testHeaderConcurrentAbortion(t, 32) } 167 168 func testHeaderConcurrentAbortion(t *testing.T, threads int) { 169 // Create a simple chain to verify 170 var ( 171 testdb, _ = ethdb.NewMemDatabase() 172 gspec = &Genesis{Config: params.TestChainConfig} 173 genesis = gspec.MustCommit(testdb) 174 //blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 1024, nil) 175 ) 176 177 chainEngine := ethash.NewFaker(testdb) 178 // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces 179 chain, _ := NewBlockChain(testdb, params.TestChainConfig, chainEngine, vm.Config{}) 180 defer chain.Stop() 181 chainEnv := NewChainEnv(params.TestChainConfig, gspec, chainEngine, chain, testdb) 182 blocks, _ := chainEnv.GenerateChain(genesis, 8, nil) 183 184 headers := make([]*types.Header, len(blocks)) 185 seals := make([]bool, len(blocks)) 186 187 for i, block := range blocks { 188 headers[i] = block.Header() 189 seals[i] = true 190 } 191 // Set the number of threads to verify on 192 old := runtime.GOMAXPROCS(threads) 193 defer runtime.GOMAXPROCS(old) 194 195 // Start the verifications and immediately abort 196 chain, _ = NewBlockChain(testdb, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond, testdb), vm.Config{}) 197 defer chain.Stop() 198 199 abort, results := chain.engine.VerifyHeaders(chain, headers, seals) 200 close(abort) 201 202 // Deplete the results channel 203 verified := 0 204 for depleted := false; !depleted; { 205 select { 206 case result := <-results: 207 if result != nil { 208 t.Errorf("header %d: validation failed: %v", verified, result) 209 } 210 verified++ 211 case <-time.After(50 * time.Millisecond): 212 depleted = true 213 } 214 } 215 // Check that abortion was honored by not processing too many POWs 216 if verified > 2*threads { 217 t.Errorf("verification count too large: have %d, want below %d", verified, 2*threads) 218 } 219 }