chain_pow_test.go 8.4 KB

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