chain_pow_test.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. package core
  17. import (
  18. "math/big"
  19. "runtime"
  20. "testing"
  21. "time"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/core/types"
  24. "github.com/ethereum/go-ethereum/ethdb"
  25. "github.com/ethereum/go-ethereum/pow"
  26. )
  27. // failPow is a non-validating proof of work implementation, that returns true
  28. // from Verify for all but one block.
  29. type failPow struct {
  30. failing uint64
  31. }
  32. func (pow failPow) Search(pow.Block, <-chan struct{}, int) (uint64, []byte) {
  33. return 0, nil
  34. }
  35. func (pow failPow) Verify(block pow.Block) bool { return block.NumberU64() != pow.failing }
  36. func (pow failPow) GetHashrate() int64 { return 0 }
  37. func (pow failPow) Turbo(bool) {}
  38. // delayedPow is a non-validating proof of work implementation, that returns true
  39. // from Verify for all blocks, but delays them the configured amount of time.
  40. type delayedPow struct {
  41. delay time.Duration
  42. }
  43. func (pow delayedPow) Search(pow.Block, <-chan struct{}, int) (uint64, []byte) {
  44. return 0, nil
  45. }
  46. func (pow delayedPow) Verify(block pow.Block) bool { time.Sleep(pow.delay); return true }
  47. func (pow delayedPow) GetHashrate() int64 { return 0 }
  48. func (pow delayedPow) Turbo(bool) {}
  49. // Tests that simple POW verification works, for both good and bad blocks.
  50. func TestPowVerification(t *testing.T) {
  51. // Create a simple chain to verify
  52. var (
  53. testdb, _ = ethdb.NewMemDatabase()
  54. genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
  55. blocks, _ = GenerateChain(genesis, testdb, 8, nil)
  56. )
  57. headers := make([]*types.Header, len(blocks))
  58. for i, block := range blocks {
  59. headers[i] = block.Header()
  60. }
  61. // Run the POW checker for blocks one-by-one, checking for both valid and invalid nonces
  62. for i := 0; i < len(blocks); i++ {
  63. for j, full := range []bool{true, false} {
  64. for k, valid := range []bool{true, false} {
  65. var results <-chan nonceCheckResult
  66. switch {
  67. case full && valid:
  68. _, results = verifyNoncesFromBlocks(FakePow{}, []*types.Block{blocks[i]})
  69. case full && !valid:
  70. _, results = verifyNoncesFromBlocks(failPow{blocks[i].NumberU64()}, []*types.Block{blocks[i]})
  71. case !full && valid:
  72. _, results = verifyNoncesFromHeaders(FakePow{}, []*types.Header{headers[i]})
  73. case !full && !valid:
  74. _, results = verifyNoncesFromHeaders(failPow{headers[i].Number.Uint64()}, []*types.Header{headers[i]})
  75. }
  76. // Wait for the verification result
  77. select {
  78. case result := <-results:
  79. if result.index != 0 {
  80. t.Errorf("test %d.%d.%d: invalid index: have %d, want 0", i, j, k, result.index)
  81. }
  82. if result.valid != valid {
  83. t.Errorf("test %d.%d.%d: validity mismatch: have %v, want %v", i, j, k, result.valid, valid)
  84. }
  85. case <-time.After(time.Second):
  86. t.Fatalf("test %d.%d.%d: verification timeout", i, j, k)
  87. }
  88. // Make sure no more data is returned
  89. select {
  90. case result := <-results:
  91. t.Fatalf("test %d.%d.%d: unexpected result returned: %v", i, j, k, result)
  92. case <-time.After(25 * time.Millisecond):
  93. }
  94. }
  95. }
  96. }
  97. }
  98. // Tests that concurrent POW verification works, for both good and bad blocks.
  99. func TestPowConcurrentVerification2(t *testing.T) { testPowConcurrentVerification(t, 2) }
  100. func TestPowConcurrentVerification8(t *testing.T) { testPowConcurrentVerification(t, 8) }
  101. func TestPowConcurrentVerification32(t *testing.T) { testPowConcurrentVerification(t, 32) }
  102. func testPowConcurrentVerification(t *testing.T, threads int) {
  103. // Create a simple chain to verify
  104. var (
  105. testdb, _ = ethdb.NewMemDatabase()
  106. genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
  107. blocks, _ = GenerateChain(genesis, testdb, 8, nil)
  108. )
  109. headers := make([]*types.Header, len(blocks))
  110. for i, block := range blocks {
  111. headers[i] = block.Header()
  112. }
  113. // Set the number of threads to verify on
  114. old := runtime.GOMAXPROCS(threads)
  115. defer runtime.GOMAXPROCS(old)
  116. // Run the POW checker for the entire block chain at once both for a valid and
  117. // also an invalid chain (enough if one is invalid, last but one (arbitrary)).
  118. for i, full := range []bool{true, false} {
  119. for j, valid := range []bool{true, false} {
  120. var results <-chan nonceCheckResult
  121. switch {
  122. case full && valid:
  123. _, results = verifyNoncesFromBlocks(FakePow{}, blocks)
  124. case full && !valid:
  125. _, results = verifyNoncesFromBlocks(failPow{uint64(len(blocks) - 1)}, blocks)
  126. case !full && valid:
  127. _, results = verifyNoncesFromHeaders(FakePow{}, headers)
  128. case !full && !valid:
  129. _, results = verifyNoncesFromHeaders(failPow{uint64(len(headers) - 1)}, headers)
  130. }
  131. // Wait for all the verification results
  132. checks := make(map[int]bool)
  133. for k := 0; k < len(blocks); k++ {
  134. select {
  135. case result := <-results:
  136. if _, ok := checks[result.index]; ok {
  137. t.Fatalf("test %d.%d.%d: duplicate results for %d", i, j, k, result.index)
  138. }
  139. if result.index < 0 || result.index >= len(blocks) {
  140. t.Fatalf("test %d.%d.%d: result %d out of bounds [%d, %d]", i, j, k, result.index, 0, len(blocks)-1)
  141. }
  142. checks[result.index] = result.valid
  143. case <-time.After(time.Second):
  144. t.Fatalf("test %d.%d.%d: verification timeout", i, j, k)
  145. }
  146. }
  147. // Check nonce check validity
  148. for k := 0; k < len(blocks); k++ {
  149. want := valid || (k != len(blocks)-2) // We chose the last but one nonce in the chain to fail
  150. if checks[k] != want {
  151. t.Errorf("test %d.%d.%d: validity mismatch: have %v, want %v", i, j, k, checks[k], want)
  152. }
  153. }
  154. // Make sure no more data is returned
  155. select {
  156. case result := <-results:
  157. t.Fatalf("test %d.%d: unexpected result returned: %v", i, j, result)
  158. case <-time.After(25 * time.Millisecond):
  159. }
  160. }
  161. }
  162. }
  163. // Tests that aborting a POW validation indeed prevents further checks from being
  164. // run, as well as checks that no left-over goroutines are leaked.
  165. func TestPowConcurrentAbortion2(t *testing.T) { testPowConcurrentAbortion(t, 2) }
  166. func TestPowConcurrentAbortion8(t *testing.T) { testPowConcurrentAbortion(t, 8) }
  167. func TestPowConcurrentAbortion32(t *testing.T) { testPowConcurrentAbortion(t, 32) }
  168. func testPowConcurrentAbortion(t *testing.T, threads int) {
  169. // Create a simple chain to verify
  170. var (
  171. testdb, _ = ethdb.NewMemDatabase()
  172. genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
  173. blocks, _ = GenerateChain(genesis, testdb, 1024, nil)
  174. )
  175. headers := make([]*types.Header, len(blocks))
  176. for i, block := range blocks {
  177. headers[i] = block.Header()
  178. }
  179. // Set the number of threads to verify on
  180. old := runtime.GOMAXPROCS(threads)
  181. defer runtime.GOMAXPROCS(old)
  182. // Run the POW checker for the entire block chain at once
  183. for i, full := range []bool{true, false} {
  184. var abort chan<- struct{}
  185. var results <-chan nonceCheckResult
  186. // Start the verifications and immediately abort
  187. if full {
  188. abort, results = verifyNoncesFromBlocks(delayedPow{time.Millisecond}, blocks)
  189. } else {
  190. abort, results = verifyNoncesFromHeaders(delayedPow{time.Millisecond}, headers)
  191. }
  192. close(abort)
  193. // Deplete the results channel
  194. verified := make(map[int]struct{})
  195. for depleted := false; !depleted; {
  196. select {
  197. case result := <-results:
  198. verified[result.index] = struct{}{}
  199. case <-time.After(50 * time.Millisecond):
  200. depleted = true
  201. }
  202. }
  203. // Check that abortion was honored by not processing too many POWs
  204. if len(verified) > 2*threads {
  205. t.Errorf("test %d: verification count too large: have %d, want below %d", i, len(verified), 2*threads)
  206. }
  207. // Check that there are no gaps in the results
  208. for j := 0; j < len(verified); j++ {
  209. if _, ok := verified[j]; !ok {
  210. t.Errorf("test %d.%d: gap found in verification results", i, j)
  211. }
  212. }
  213. }
  214. }