Ver código fonte

core, consensus: pluggable consensus engines (#3817)

This commit adds pluggable consensus engines to go-ethereum. In short, it
introduces a generic consensus interface, and refactors the entire codebase to
use this interface.
Péter Szilágyi 8 anos atrás
pai
commit
09777952ee
61 arquivos alterados com 1682 adições e 1427 exclusões
  1. 2 2
      accounts/abi/bind/backends/simulated.go
  2. 1 1
      cmd/evm/disasm.go
  3. 9 1
      cmd/geth/main.go
  4. 2 2
      cmd/geth/misccmd.go
  5. 5 5
      cmd/utils/flags.go
  6. 94 0
      consensus/consensus.go
  7. 1 1
      consensus/ethash/algorithm.go
  8. 1 1
      consensus/ethash/algorithm_go1.7.go
  9. 1 1
      consensus/ethash/algorithm_go1.8.go
  10. 1 1
      consensus/ethash/algorithm_go1.8_test.go
  11. 3 14
      consensus/ethash/algorithm_test.go
  12. 496 0
      consensus/ethash/consensus.go
  13. 79 0
      consensus/ethash/consensus_test.go
  14. 88 90
      consensus/ethash/ethash.go
  15. 40 0
      consensus/ethash/ethash_test.go
  16. 146 0
      consensus/ethash/sealer.go
  17. 1 1
      consensus/ethash/xor.go
  18. 85 0
      consensus/misc/dao.go
  19. 43 0
      consensus/misc/forks.go
  20. 3 3
      core/bench_test.go
  21. 15 260
      core/block_validator.go
  22. 159 44
      core/block_validator_test.go
  23. 26 36
      core/blockchain.go
  24. 48 49
      core/blockchain_test.go
  25. 7 6
      core/chain_makers.go
  26. 2 2
      core/chain_makers_test.go
  27. 0 87
      core/chain_pow.go
  28. 0 238
      core/chain_pow_test.go
  29. 7 7
      core/dao_test.go
  30. 5 55
      core/database_util_test.go
  31. 2 2
      core/genesis_test.go
  32. 37 112
      core/headerchain.go
  33. 11 33
      core/state_processor.go
  34. 8 22
      core/types.go
  35. 5 6
      core/types/block.go
  36. 52 41
      eth/api.go
  37. 24 25
      eth/backend.go
  38. 6 6
      eth/fetcher/fetcher.go
  39. 3 3
      eth/fetcher/fetcher_test.go
  40. 6 5
      eth/handler.go
  41. 2 2
      eth/handler_test.go
  42. 7 7
      eth/helper_test.go
  43. 2 2
      internal/ethapi/api.go
  44. 5 7
      les/backend.go
  45. 2 2
      les/handler.go
  46. 8 8
      les/helper_test.go
  47. 1 1
      les/server.go
  48. 5 27
      light/lightchain.go
  49. 13 21
      light/lightchain_test.go
  50. 4 7
      light/odr_test.go
  51. 5 8
      light/txpool_test.go
  52. 3 3
      log/format.go
  53. 20 27
      miner/agent.go
  54. 14 17
      miner/miner.go
  55. 20 13
      miner/remote_agent.go
  56. 4 5
      miner/unconfirmed.go
  57. 38 46
      miner/worker.go
  58. 2 2
      params/util.go
  59. 0 58
      pow/pow.go
  60. 2 2
      tests/block_test_util.go
  61. 1 0
      trie/iterator.go

+ 2 - 2
accounts/abi/bind/backends/simulated.go

@@ -27,6 +27,7 @@ import (
 	"github.com/ethereum/go-ethereum/accounts/abi/bind"
 	"github.com/ethereum/go-ethereum/accounts/abi/bind"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -34,7 +35,6 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
 // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
@@ -61,7 +61,7 @@ func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
 	database, _ := ethdb.NewMemDatabase()
 	database, _ := ethdb.NewMemDatabase()
 	genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
 	genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
 	genesis.MustCommit(database)
 	genesis.MustCommit(database)
-	blockchain, _ := core.NewBlockChain(database, genesis.Config, new(pow.FakePow), new(event.TypeMux), vm.Config{})
+	blockchain, _ := core.NewBlockChain(database, genesis.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 	backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config}
 	backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config}
 	backend.rollback()
 	backend.rollback()
 	return backend
 	return backend

+ 1 - 1
cmd/evm/disasm.go

@@ -20,10 +20,10 @@ import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
+	"strings"
 
 
 	"github.com/ethereum/go-ethereum/core/asm"
 	"github.com/ethereum/go-ethereum/core/asm"
 	cli "gopkg.in/urfave/cli.v1"
 	cli "gopkg.in/urfave/cli.v1"
-	"strings"
 )
 )
 
 
 var disasmCommand = cli.Command{
 var disasmCommand = cli.Command{

+ 9 - 1
cmd/geth/main.go

@@ -303,7 +303,15 @@ func startNode(ctx *cli.Context, stack *node.Node) {
 		if err := stack.Service(&ethereum); err != nil {
 		if err := stack.Service(&ethereum); err != nil {
 			utils.Fatalf("ethereum service not running: %v", err)
 			utils.Fatalf("ethereum service not running: %v", err)
 		}
 		}
-		if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil {
+		if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
+			type threaded interface {
+				SetThreads(threads int)
+			}
+			if th, ok := ethereum.Engine().(threaded); ok {
+				th.SetThreads(threads)
+			}
+		}
+		if err := ethereum.StartMining(); err != nil {
 			utils.Fatalf("Failed to start mining: %v", err)
 			utils.Fatalf("Failed to start mining: %v", err)
 		}
 		}
 	}
 	}

+ 2 - 2
cmd/geth/misccmd.go

@@ -26,9 +26,9 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/ethereum/go-ethereum/cmd/utils"
 	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"gopkg.in/urfave/cli.v1"
 	"gopkg.in/urfave/cli.v1"
 )
 )
 
 
@@ -87,7 +87,7 @@ func makedag(ctx *cli.Context) error {
 				utils.Fatalf("Can't find dir")
 				utils.Fatalf("Can't find dir")
 			}
 			}
 			fmt.Println("making DAG, this could take awhile...")
 			fmt.Println("making DAG, this could take awhile...")
-			pow.MakeDataset(blockNum, dir)
+			ethash.MakeDataset(blockNum, dir)
 		}
 		}
 	default:
 	default:
 		wrongArgs()
 		wrongArgs()

+ 5 - 5
cmd/utils/flags.go

@@ -32,6 +32,7 @@ import (
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/accounts/keystore"
 	"github.com/ethereum/go-ethereum/accounts/keystore"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
@@ -49,7 +50,6 @@ import (
 	"github.com/ethereum/go-ethereum/p2p/nat"
 	"github.com/ethereum/go-ethereum/p2p/nat"
 	"github.com/ethereum/go-ethereum/p2p/netutil"
 	"github.com/ethereum/go-ethereum/p2p/netutil"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rpc"
 	"github.com/ethereum/go-ethereum/rpc"
 	whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
 	whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
 	"gopkg.in/urfave/cli.v1"
 	"gopkg.in/urfave/cli.v1"
@@ -149,7 +149,7 @@ var (
 	}
 	}
 	TestNetFlag = cli.BoolFlag{
 	TestNetFlag = cli.BoolFlag{
 		Name:  "testnet",
 		Name:  "testnet",
-		Usage: "Ropsten network: pre-configured test network",
+		Usage: "Ropsten network: pre-configured proof-of-work test network",
 	}
 	}
 	DevModeFlag = cli.BoolFlag{
 	DevModeFlag = cli.BoolFlag{
 		Name:  "dev",
 		Name:  "dev",
@@ -921,16 +921,16 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
 	var err error
 	var err error
 	chainDb = MakeChainDatabase(ctx, stack)
 	chainDb = MakeChainDatabase(ctx, stack)
 
 
-	seal := pow.PoW(pow.FakePow{})
+	engine := ethash.NewFaker()
 	if !ctx.GlobalBool(FakePoWFlag.Name) {
 	if !ctx.GlobalBool(FakePoWFlag.Name) {
-		seal = pow.NewFullEthash("", 1, 0, "", 1, 0)
+		engine = ethash.New("", 1, 0, "", 1, 0)
 	}
 	}
 	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
 	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
 	if err != nil {
 	if err != nil {
 		Fatalf("%v", err)
 		Fatalf("%v", err)
 	}
 	}
 	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
 	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
-	chain, err = core.NewBlockChain(chainDb, config, seal, new(event.TypeMux), vmcfg)
+	chain, err = core.NewBlockChain(chainDb, config, engine, new(event.TypeMux), vmcfg)
 	if err != nil {
 	if err != nil {
 		Fatalf("Can't create BlockChain: %v", err)
 		Fatalf("Can't create BlockChain: %v", err)
 	}
 	}

+ 94 - 0
consensus/consensus.go

@@ -0,0 +1,94 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Package consensus implements different Ethereum consensus engines.
+package consensus
+
+import (
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/params"
+	"github.com/ethereum/go-ethereum/rpc"
+)
+
+// ChainReader defines a small collection of methods needed to access the local
+// blockchain during header and/or uncle verification.
+type ChainReader interface {
+	// Config retrieves the blockchain's chain configuration.
+	Config() *params.ChainConfig
+
+	// CurrentHeader retrieves the current header from the local chain.
+	CurrentHeader() *types.Header
+
+	// GetHeader retrieves a block header from the database by hash and number.
+	GetHeader(hash common.Hash, number uint64) *types.Header
+
+	// GetHeaderByNumber retrieves a block header from the database by number.
+	GetHeaderByNumber(number uint64) *types.Header
+
+	// GetBlock retrieves a block from the database by hash and number.
+	GetBlock(hash common.Hash, number uint64) *types.Block
+}
+
+// Engine is an algorithm agnostic consensus engine.
+type Engine interface {
+	// VerifyHeader checks whether a header conforms to the consensus rules of a
+	// given engine. Verifying the seal may be done optionally here, or explicitly
+	// via the VerifySeal method.
+	VerifyHeader(chain ChainReader, header *types.Header, seal bool) error
+
+	// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
+	// concurrently. The method returns a quit channel to abort the operations and
+	// a results channel to retrieve the async verifications (the order is that of
+	// the input slice).
+	VerifyHeaders(chain ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error)
+
+	// VerifyUncles verifies that the given block's uncles conform to the consensus
+	// rules of a given engine.
+	VerifyUncles(chain ChainReader, block *types.Block) error
+
+	// VerifySeal checks whether the crypto seal on a header is valid according to
+	// the consensus rules of the given engine.
+	VerifySeal(chain ChainReader, header *types.Header) error
+
+	// Prepare initializes the consensus fields of a block header according to the
+	// rules of a particular engine. The changes are executed inline.
+	Prepare(chain ChainReader, header *types.Header) error
+
+	// Finalize runs any post-transaction state modifications (e.g. block rewards)
+	// and assembles the final block.
+	//
+	// Note, the block header and state database might be updated to reflect any
+	// consensus rules that happen at finalization (e.g. block rewards).
+	Finalize(chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
+		uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error)
+
+	// Seal generates a new block for the given input block with the local miner's
+	// seal place on top.
+	Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error)
+
+	// APIs returns the RPC APIs this consensus engine provides.
+	APIs(chain ChainReader) []rpc.API
+}
+
+// PoW is a consensus engine based on proof-of-work.
+type PoW interface {
+	Engine
+
+	// Hashrate returns the current mining hashrate of a PoW consensus engine.
+	Hashrate() float64
+}

+ 1 - 1
pow/ethash_algo.go → consensus/ethash/algorithm.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
 
-package pow
+package ethash
 
 
 import (
 import (
 	"encoding/binary"
 	"encoding/binary"

+ 1 - 1
pow/ethash_algo_go1.7.go → consensus/ethash/algorithm_go1.7.go

@@ -16,7 +16,7 @@
 
 
 // +build !go1.8
 // +build !go1.8
 
 
-package pow
+package ethash
 
 
 // cacheSize calculates and returns the size of the ethash verification cache that
 // cacheSize calculates and returns the size of the ethash verification cache that
 // belongs to a certain block number. The cache size grows linearly, however, we
 // belongs to a certain block number. The cache size grows linearly, however, we

+ 1 - 1
pow/ethash_algo_go1.8.go → consensus/ethash/algorithm_go1.8.go

@@ -16,7 +16,7 @@
 
 
 // +build go1.8
 // +build go1.8
 
 
-package pow
+package ethash
 
 
 import "math/big"
 import "math/big"
 
 

+ 1 - 1
pow/ethash_algo_go1.8_test.go → consensus/ethash/algorithm_go1.8_test.go

@@ -16,7 +16,7 @@
 
 
 // +build go1.8
 // +build go1.8
 
 
-package pow
+package ethash
 
 
 import "testing"
 import "testing"
 
 

+ 3 - 14
pow/ethash_algo_test.go → consensus/ethash/algorithm_test.go

@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU Lesser General Public License
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
 
-package pow
+package ethash
 
 
 import (
 import (
 	"bytes"
 	"bytes"
@@ -704,8 +704,8 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) {
 		go func(idx int) {
 		go func(idx int) {
 			defer pend.Done()
 			defer pend.Done()
 
 
-			ethash := NewFullEthash(cachedir, 0, 1, "", 0, 0)
-			if err := ethash.Verify(block); err != nil {
+			ethash := New(cachedir, 0, 1, "", 0, 0)
+			if err := ethash.VerifySeal(nil, block.Header()); err != nil {
 				t.Errorf("proc %d: block verification failed: %v", idx, err)
 				t.Errorf("proc %d: block verification failed: %v", idx, err)
 			}
 			}
 		}(i)
 		}(i)
@@ -713,17 +713,6 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) {
 	pend.Wait()
 	pend.Wait()
 }
 }
 
 
-func TestTestMode(t *testing.T) {
-	head := &types.Header{Difficulty: big.NewInt(100)}
-	ethash := NewTestEthash()
-	nonce, mix := ethash.Search(types.NewBlockWithHeader(head), nil)
-	head.Nonce = types.EncodeNonce(nonce)
-	copy(head.MixDigest[:], mix)
-	if err := ethash.Verify(types.NewBlockWithHeader(head)); err != nil {
-		t.Error("unexpected Verify error:", err)
-	}
-}
-
 // Benchmarks the cache generation performance.
 // Benchmarks the cache generation performance.
 func BenchmarkCacheGeneration(b *testing.B) {
 func BenchmarkCacheGeneration(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 	for i := 0; i < b.N; i++ {

+ 496 - 0
consensus/ethash/consensus.go

@@ -0,0 +1,496 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package ethash
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"math/big"
+	"runtime"
+	"sync/atomic"
+	"time"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/consensus"
+	"github.com/ethereum/go-ethereum/consensus/misc"
+	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/params"
+	set "gopkg.in/fatih/set.v0"
+)
+
+// Ethash proof-of-work protocol constants.
+var (
+	blockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
+	maxUncles            = 2                 // Maximum number of uncles allowed in a single block
+)
+
+var (
+	ErrInvalidChain        = errors.New("invalid header chain")
+	ErrParentUnknown       = errors.New("parent not known locally")
+	ErrFutureBlock         = errors.New("block in the future")
+	ErrLargeBlockTimestamp = errors.New("timestamp too big")
+	ErrZeroBlockTime       = errors.New("timestamp equals parent's")
+	ErrInvalidNumber       = errors.New("invalid block number")
+	ErrTooManyUncles       = errors.New("too many uncles")
+	ErrDuplicateUncle      = errors.New("duplicate uncle")
+	ErrUncleIsAncestor     = errors.New("uncle is ancestor")
+	ErrDanglingUncle       = errors.New("uncle's parent is not ancestor")
+	ErrNonceOutOfRange     = errors.New("nonce out of range")
+	ErrInvalidDifficulty   = errors.New("non-positive difficulty")
+	ErrInvalidMixDigest    = errors.New("invalid mix digest")
+	ErrInvalidPoW          = errors.New("invalid proof-of-work")
+)
+
+// VerifyHeader checks whether a header conforms to the consensus rules of the
+// stock Ethereum ethash engine.
+func (ethash *Ethash) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error {
+	// If we're running a full engine faking, accept any input as valid
+	if ethash.fakeFull {
+		return nil
+	}
+	// Short circuit if the header is known, or it's parent not
+	number := header.Number.Uint64()
+	if chain.GetHeader(header.Hash(), number) != nil {
+		return nil
+	}
+	parent := chain.GetHeader(header.ParentHash, number-1)
+	if parent == nil {
+		return ErrParentUnknown
+	}
+	// Sanity checks passed, do a proper verification
+	return ethash.verifyHeader(chain, header, parent, false, seal)
+}
+
+// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
+// concurrently. The method returns a quit channel to abort the operations and
+// a results channel to retrieve the async verifications.
+func (ethash *Ethash) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) {
+	// If we're running a full engine faking, accept any input as valid
+	if ethash.fakeFull {
+		abort, results := make(chan struct{}), make(chan error, len(headers))
+		for i := 0; i < len(headers); i++ {
+			results <- nil
+		}
+		return abort, results
+	}
+	// Spawn as many workers as allowed threads
+	workers := runtime.GOMAXPROCS(0)
+	if len(headers) < workers {
+		workers = len(headers)
+	}
+	// Create a task channel and spawn the verifiers
+	type result struct {
+		index int
+		err   error
+	}
+	inputs := make(chan int, workers)
+	outputs := make(chan result, len(headers))
+
+	var badblock uint64
+	for i := 0; i < workers; i++ {
+		go func() {
+			for index := range inputs {
+				// If we've found a bad block already before this, stop validating
+				if bad := atomic.LoadUint64(&badblock); bad != 0 && bad <= headers[index].Number.Uint64() {
+					outputs <- result{index: index, err: ErrInvalidChain}
+					continue
+				}
+				// We need to look up the first parent
+				var parent *types.Header
+				if index == 0 {
+					parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1)
+				} else if headers[index-1].Hash() == headers[index].ParentHash {
+					parent = headers[index-1]
+				}
+				// Ensure the validation is useful and execute it
+				var failure error
+				switch {
+				case chain.GetHeader(headers[index].Hash(), headers[index].Number.Uint64()-1) != nil:
+					outputs <- result{index: index, err: nil}
+				case parent == nil:
+					failure = ErrParentUnknown
+					outputs <- result{index: index, err: failure}
+				default:
+					failure = ethash.verifyHeader(chain, headers[index], parent, false, seals[index])
+					outputs <- result{index: index, err: failure}
+				}
+				// If a validation failure occurred, mark subsequent blocks invalid
+				if failure != nil {
+					number := headers[index].Number.Uint64()
+					if prev := atomic.LoadUint64(&badblock); prev == 0 || prev > number {
+						// This two step atomic op isn't thread-safe in that `badblock` might end
+						// up slightly higher than the block number of the first failure (if many
+						// workers try to write at the same time), but it's fine as we're mostly
+						// interested to avoid large useless work, we don't care about 1-2 extra
+						// runs. Doing "full thread safety" would involve mutexes, which would be
+						// a noticeable sync overhead on the fast spinning worker routines.
+						atomic.StoreUint64(&badblock, number)
+					}
+				}
+			}
+		}()
+	}
+	// Feed item indices to the workers until done, sorting and feeding the results to the caller
+	dones := make([]bool, len(headers))
+	errors := make([]error, len(headers))
+
+	abort := make(chan struct{})
+	returns := make(chan error, len(headers))
+
+	go func() {
+		defer close(inputs)
+
+		input, output := 0, 0
+		for i := 0; i < len(headers)*2; i++ {
+			var res result
+
+			// If there are tasks left, push to workers
+			if input < len(headers) {
+				select {
+				case inputs <- input:
+					input++
+					continue
+				case <-abort:
+					return
+				case res = <-outputs:
+				}
+			} else {
+				// Otherwise keep waiting for results
+				select {
+				case <-abort:
+					return
+				case res = <-outputs:
+				}
+			}
+			// A result arrived, save and propagate if next
+			dones[res.index], errors[res.index] = true, res.err
+			for output < len(headers) && dones[output] {
+				returns <- errors[output]
+				output++
+			}
+		}
+	}()
+	return abort, returns
+}
+
+// VerifyUncles verifies that the given block's uncles conform to the consensus
+// rules of the stock Ethereum ethash engine.
+func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
+	// If we're running a full engine faking, accept any input as valid
+	if ethash.fakeFull {
+		return nil
+	}
+	// Verify that there are at most 2 uncles included in this block
+	if len(block.Uncles()) > maxUncles {
+		return ErrTooManyUncles
+	}
+	// Gather the set of past uncles and ancestors
+	uncles, ancestors := set.New(), make(map[common.Hash]*types.Header)
+
+	number, parent := block.NumberU64()-1, block.ParentHash()
+	for i := 0; i < 7; i++ {
+		ancestor := chain.GetBlock(parent, number)
+		if ancestor == nil {
+			break
+		}
+		ancestors[ancestor.Hash()] = ancestor.Header()
+		for _, uncle := range ancestor.Uncles() {
+			uncles.Add(uncle.Hash())
+		}
+		parent, number = ancestor.ParentHash(), number-1
+	}
+	ancestors[block.Hash()] = block.Header()
+	uncles.Add(block.Hash())
+
+	// Verify each of the uncles that it's recent, but not an ancestor
+	for _, uncle := range block.Uncles() {
+		// Make sure every uncle is rewarded only once
+		hash := uncle.Hash()
+		if uncles.Has(hash) {
+			return ErrDuplicateUncle
+		}
+		uncles.Add(hash)
+
+		// Make sure the uncle has a valid ancestry
+		if ancestors[hash] != nil {
+			return ErrUncleIsAncestor
+		}
+		if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == block.ParentHash() {
+			return ErrDanglingUncle
+		}
+		if err := ethash.verifyHeader(chain, uncle, ancestors[uncle.ParentHash], true, true); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// verifyHeader checks whether a header conforms to the consensus rules of the
+// stock Ethereum ethash engine.
+//
+// See YP section 4.3.4. "Block Header Validity"
+func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *types.Header, uncle bool, seal bool) error {
+	// Ensure that the header's extra-data section is of a reasonable size
+	if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
+		return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize)
+	}
+	// Verify the header's timestamp
+	if uncle {
+		if header.Time.Cmp(math.MaxBig256) > 0 {
+			return ErrLargeBlockTimestamp
+		}
+	} else {
+		if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 {
+			return ErrFutureBlock
+		}
+	}
+	if header.Time.Cmp(parent.Time) <= 0 {
+		return ErrZeroBlockTime
+	}
+	// Verify the block's difficulty based in it's timestamp and parent's difficulty
+	expected := CalcDifficulty(chain.Config(), header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty)
+	if expected.Cmp(header.Difficulty) != 0 {
+		return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected)
+	}
+	// Verify that the gas limit remains within allowed bounds
+	diff := new(big.Int).Set(parent.GasLimit)
+	diff = diff.Sub(diff, header.GasLimit)
+	diff.Abs(diff)
+
+	limit := new(big.Int).Set(parent.GasLimit)
+	limit = limit.Div(limit, params.GasLimitBoundDivisor)
+
+	if diff.Cmp(limit) >= 0 || header.GasLimit.Cmp(params.MinGasLimit) < 0 {
+		return fmt.Errorf("invalid gas limit: have %v, want %v += %v", header.GasLimit, parent.GasLimit, limit)
+	}
+	// Verify that the block number is parent's +1
+	if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
+		return ErrInvalidNumber
+	}
+	// Verify the engine specific seal securing the block
+	if seal {
+		if err := ethash.VerifySeal(chain, header); err != nil {
+			return err
+		}
+	}
+	// If all checks passed, validate any special fields for hard forks
+	if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil {
+		return err
+	}
+	if err := misc.VerifyForkHashes(chain.Config(), header, uncle); err != nil {
+		return err
+	}
+	return nil
+}
+
+// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
+// that a new block should have when created at time given the parent block's time
+// and difficulty.
+//
+// TODO (karalabe): Move the chain maker into this package and make this private!
+func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
+	if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
+		return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
+	}
+	return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff)
+}
+
+// Some weird constants to avoid constant memory allocs for them.
+var (
+	expDiffPeriod = big.NewInt(100000)
+	big10         = big.NewInt(10)
+	bigMinus99    = big.NewInt(-99)
+)
+
+// calcDifficultyHomestead is the difficulty adjustment algorithm. It returns
+// the difficulty that a new block should have when created at time given the
+// parent block's time and difficulty. The calculation uses the Homestead rules.
+func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
+	// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki
+	// algorithm:
+	// diff = (parent_diff +
+	//         (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
+	//        ) + 2^(periodCount - 2)
+
+	bigTime := new(big.Int).SetUint64(time)
+	bigParentTime := new(big.Int).SetUint64(parentTime)
+
+	// holds intermediate values to make the algo easier to read & audit
+	x := new(big.Int)
+	y := new(big.Int)
+
+	// 1 - (block_timestamp -parent_timestamp) // 10
+	x.Sub(bigTime, bigParentTime)
+	x.Div(x, big10)
+	x.Sub(common.Big1, x)
+
+	// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
+	if x.Cmp(bigMinus99) < 0 {
+		x.Set(bigMinus99)
+	}
+	// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
+	y.Div(parentDiff, params.DifficultyBoundDivisor)
+	x.Mul(y, x)
+	x.Add(parentDiff, x)
+
+	// minimum difficulty can ever be (before exponential factor)
+	if x.Cmp(params.MinimumDifficulty) < 0 {
+		x.Set(params.MinimumDifficulty)
+	}
+	// for the exponential factor
+	periodCount := new(big.Int).Add(parentNumber, common.Big1)
+	periodCount.Div(periodCount, expDiffPeriod)
+
+	// the exponential factor, commonly referred to as "the bomb"
+	// diff = diff + 2^(periodCount - 2)
+	if periodCount.Cmp(common.Big1) > 0 {
+		y.Sub(periodCount, common.Big2)
+		y.Exp(common.Big2, y, nil)
+		x.Add(x, y)
+	}
+	return x
+}
+
+// calcDifficultyFrontier is the difficulty adjustment algorithm. It returns the
+// difficulty that a new block should have when created at time given the parent
+// block's time and difficulty. The calculation uses the Frontier rules.
+func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
+	diff := new(big.Int)
+	adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
+	bigTime := new(big.Int)
+	bigParentTime := new(big.Int)
+
+	bigTime.SetUint64(time)
+	bigParentTime.SetUint64(parentTime)
+
+	if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
+		diff.Add(parentDiff, adjust)
+	} else {
+		diff.Sub(parentDiff, adjust)
+	}
+	if diff.Cmp(params.MinimumDifficulty) < 0 {
+		diff.Set(params.MinimumDifficulty)
+	}
+
+	periodCount := new(big.Int).Add(parentNumber, common.Big1)
+	periodCount.Div(periodCount, expDiffPeriod)
+	if periodCount.Cmp(common.Big1) > 0 {
+		// diff = diff + 2^(periodCount - 2)
+		expDiff := periodCount.Sub(periodCount, common.Big2)
+		expDiff.Exp(common.Big2, expDiff, nil)
+		diff.Add(diff, expDiff)
+		diff = math.BigMax(diff, params.MinimumDifficulty)
+	}
+	return diff
+}
+
+// VerifySeal implements consensus.Engine, checking whether the given block satisfies
+// the PoW difficulty requirements.
+func (ethash *Ethash) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
+	// If we're running a fake PoW, accept any seal as valid
+	if ethash.fakeMode {
+		time.Sleep(ethash.fakeDelay)
+		if ethash.fakeFail == header.Number.Uint64() {
+			return ErrInvalidPoW
+		}
+		return nil
+	}
+	// If we're running a shared PoW, delegate verification to it
+	if ethash.shared != nil {
+		return ethash.shared.VerifySeal(chain, header)
+	}
+	// Sanity check that the block number is below the lookup table size (60M blocks)
+	number := header.Number.Uint64()
+	if number/epochLength >= uint64(len(cacheSizes)) {
+		// Go < 1.7 cannot calculate new cache/dataset sizes (no fast prime check)
+		return ErrNonceOutOfRange
+	}
+	// Ensure that we have a valid difficulty for the block
+	if header.Difficulty.Sign() <= 0 {
+		return ErrInvalidDifficulty
+	}
+	// Recompute the digest and PoW value and verify against the header
+	cache := ethash.cache(number)
+
+	size := datasetSize(number)
+	if ethash.tester {
+		size = 32 * 1024
+	}
+	digest, result := hashimotoLight(size, cache, header.HashNoNonce().Bytes(), header.Nonce.Uint64())
+	if !bytes.Equal(header.MixDigest[:], digest) {
+		return ErrInvalidMixDigest
+	}
+	target := new(big.Int).Div(maxUint256, header.Difficulty)
+	if new(big.Int).SetBytes(result).Cmp(target) > 0 {
+		return ErrInvalidPoW
+	}
+	return nil
+}
+
+// Prepare implements consensus.Engine, initializing the difficulty field of a
+// header to conform to the ethash protocol. The changes are done inline.
+func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header) error {
+	parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
+	if parent == nil {
+		return ErrParentUnknown
+	}
+	header.Difficulty = CalcDifficulty(chain.Config(), header.Time.Uint64(),
+		parent.Time.Uint64(), parent.Number, parent.Difficulty)
+
+	return nil
+}
+
+// Finalize implements consensus.Engine, accumulating the block and uncle rewards,
+// setting the final state and assembling the block.
+func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
+	// Accumulate any block and uncle rewards and commit the final state root
+	AccumulateRewards(state, header, uncles)
+	header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
+
+	// Header seems complete, assemble into a block and return
+	return types.NewBlock(header, txs, uncles, receipts), nil
+}
+
+// Some weird constants to avoid constant memory allocs for them.
+var (
+	big8  = big.NewInt(8)
+	big32 = big.NewInt(32)
+)
+
+// AccumulateRewards credits the coinbase of the given block with the mining
+// reward. The total reward consists of the static block reward and rewards for
+// included uncles. The coinbase of each uncle block is also rewarded.
+//
+// TODO (karalabe): Move the chain maker into this package and make this private!
+func AccumulateRewards(state *state.StateDB, header *types.Header, uncles []*types.Header) {
+	reward := new(big.Int).Set(blockReward)
+	r := new(big.Int)
+	for _, uncle := range uncles {
+		r.Add(uncle.Number, big8)
+		r.Sub(r, header.Number)
+		r.Mul(r, blockReward)
+		r.Div(r, big8)
+		state.AddBalance(uncle.Coinbase, r)
+
+		r.Div(blockReward, big32)
+		reward.Add(reward, r)
+	}
+	state.AddBalance(header.Coinbase, reward)
+}

+ 79 - 0
consensus/ethash/consensus_test.go

@@ -0,0 +1,79 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package ethash
+
+import (
+	"encoding/json"
+	"math/big"
+	"os"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/params"
+)
+
+type diffTest struct {
+	ParentTimestamp    uint64
+	ParentDifficulty   *big.Int
+	CurrentTimestamp   uint64
+	CurrentBlocknumber *big.Int
+	CurrentDifficulty  *big.Int
+}
+
+func (d *diffTest) UnmarshalJSON(b []byte) (err error) {
+	var ext struct {
+		ParentTimestamp    string
+		ParentDifficulty   string
+		CurrentTimestamp   string
+		CurrentBlocknumber string
+		CurrentDifficulty  string
+	}
+	if err := json.Unmarshal(b, &ext); err != nil {
+		return err
+	}
+
+	d.ParentTimestamp = math.MustParseUint64(ext.ParentTimestamp)
+	d.ParentDifficulty = math.MustParseBig256(ext.ParentDifficulty)
+	d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp)
+	d.CurrentBlocknumber = math.MustParseBig256(ext.CurrentBlocknumber)
+	d.CurrentDifficulty = math.MustParseBig256(ext.CurrentDifficulty)
+
+	return nil
+}
+
+func TestCalcDifficulty(t *testing.T) {
+	file, err := os.Open("../../tests/files/BasicTests/difficulty.json")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer file.Close()
+
+	tests := make(map[string]diffTest)
+	err = json.NewDecoder(file).Decode(&tests)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	config := &params.ChainConfig{HomesteadBlock: big.NewInt(1150000)}
+	for name, test := range tests {
+		number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
+		diff := CalcDifficulty(config, test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty)
+		if diff.Cmp(test.CurrentDifficulty) != 0 {
+			t.Error(name, "failed. Expected", test.CurrentDifficulty, "and calculated", diff)
+		}
+	}
+}

+ 88 - 90
pow/ethash.go → consensus/ethash/ethash.go

@@ -14,10 +14,10 @@
 // You should have received a copy of the GNU Lesser General Public License
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
 
-package pow
+// Package ethash implements the ethash proof-of-work consensus engine.
+package ethash
 
 
 import (
 import (
-	"bytes"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"math"
 	"math"
@@ -32,24 +32,20 @@ import (
 	"unsafe"
 	"unsafe"
 
 
 	mmap "github.com/edsrzf/mmap-go"
 	mmap "github.com/edsrzf/mmap-go"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
+	"github.com/ethereum/go-ethereum/rpc"
 	metrics "github.com/rcrowley/go-metrics"
 	metrics "github.com/rcrowley/go-metrics"
 )
 )
 
 
-var (
-	ErrInvalidDumpMagic  = errors.New("invalid dump magic")
-	ErrNonceOutOfRange   = errors.New("nonce out of range")
-	ErrInvalidDifficulty = errors.New("non-positive difficulty")
-	ErrInvalidMixDigest  = errors.New("invalid mix digest")
-	ErrInvalidPoW        = errors.New("pow difficulty invalid")
-)
+var ErrInvalidDumpMagic = errors.New("invalid dump magic")
 
 
 var (
 var (
 	// maxUint256 is a big integer representing 2^256-1
 	// maxUint256 is a big integer representing 2^256-1
 	maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
 	maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
 
 
 	// sharedEthash is a full instance that can be shared between multiple users.
 	// sharedEthash is a full instance that can be shared between multiple users.
-	sharedEthash = NewFullEthash("", 3, 0, "", 1, 0)
+	sharedEthash = New("", 3, 0, "", 1, 0)
 
 
 	// algorithmRevision is the data structure version used for file naming.
 	// algorithmRevision is the data structure version used for file naming.
 	algorithmRevision = 23
 	algorithmRevision = 23
@@ -321,7 +317,8 @@ func MakeDataset(block uint64, dir string) {
 	d.release()
 	d.release()
 }
 }
 
 
-// Ethash is a PoW data struture implementing the ethash algorithm.
+// Ethash is a consensus engine based on proot-of-work implementing the ethash
+// algorithm.
 type Ethash struct {
 type Ethash struct {
 	cachedir     string // Data directory to store the verification caches
 	cachedir     string // Data directory to store the verification caches
 	cachesinmem  int    // Number of caches to keep in memory
 	cachesinmem  int    // Number of caches to keep in memory
@@ -334,15 +331,26 @@ type Ethash struct {
 	fcache   *cache              // Pre-generated cache for the estimated future epoch
 	fcache   *cache              // Pre-generated cache for the estimated future epoch
 	datasets map[uint64]*dataset // In memory datasets to avoid regenerating too often
 	datasets map[uint64]*dataset // In memory datasets to avoid regenerating too often
 	fdataset *dataset            // Pre-generated dataset for the estimated future epoch
 	fdataset *dataset            // Pre-generated dataset for the estimated future epoch
-	lock     sync.Mutex          // Ensures thread safety for the in-memory caches
 
 
+	// Mining related fields
+	rand     *rand.Rand    // Properly seeded random source for nonces
+	threads  int           // Number of threads to mine on if mining
+	update   chan struct{} // Notification channel to update mining parameters
 	hashrate metrics.Meter // Meter tracking the average hashrate
 	hashrate metrics.Meter // Meter tracking the average hashrate
 
 
-	tester bool // Flag whether to use a smaller test dataset
+	// The fields below are hooks for testing
+	tester    bool          // Flag whether to use a smaller test dataset
+	shared    *Ethash       // Shared PoW verifier to avoid cache regeneration
+	fakeMode  bool          // Flag whether to disable PoW checking
+	fakeFull  bool          // Flag whether to disable all consensus rules
+	fakeFail  uint64        // Block number which fails PoW check even in fake mode
+	fakeDelay time.Duration // Time delay to sleep for before returning from verify
+
+	lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields
 }
 }
 
 
-// NewFullEthash creates a full sized ethash PoW scheme.
-func NewFullEthash(cachedir string, cachesinmem, cachesondisk int, dagdir string, dagsinmem, dagsondisk int) PoW {
+// New creates a full sized ethash PoW scheme.
+func New(cachedir string, cachesinmem, cachesondisk int, dagdir string, dagsinmem, dagsondisk int) *Ethash {
 	if cachesinmem <= 0 {
 	if cachesinmem <= 0 {
 		log.Warn("One ethash cache must alwast be in memory", "requested", cachesinmem)
 		log.Warn("One ethash cache must alwast be in memory", "requested", cachesinmem)
 		cachesinmem = 1
 		cachesinmem = 1
@@ -362,58 +370,55 @@ func NewFullEthash(cachedir string, cachesinmem, cachesondisk int, dagdir string
 		dagsondisk:   dagsondisk,
 		dagsondisk:   dagsondisk,
 		caches:       make(map[uint64]*cache),
 		caches:       make(map[uint64]*cache),
 		datasets:     make(map[uint64]*dataset),
 		datasets:     make(map[uint64]*dataset),
+		update:       make(chan struct{}),
 		hashrate:     metrics.NewMeter(),
 		hashrate:     metrics.NewMeter(),
 	}
 	}
 }
 }
 
 
-// NewTestEthash creates a small sized ethash PoW scheme useful only for testing
+// NewTester creates a small sized ethash PoW scheme useful only for testing
 // purposes.
 // purposes.
-func NewTestEthash() PoW {
+func NewTester() *Ethash {
 	return &Ethash{
 	return &Ethash{
 		cachesinmem: 1,
 		cachesinmem: 1,
 		caches:      make(map[uint64]*cache),
 		caches:      make(map[uint64]*cache),
 		datasets:    make(map[uint64]*dataset),
 		datasets:    make(map[uint64]*dataset),
 		tester:      true,
 		tester:      true,
+		update:      make(chan struct{}),
 		hashrate:    metrics.NewMeter(),
 		hashrate:    metrics.NewMeter(),
 	}
 	}
 }
 }
 
 
-// NewSharedEthash creates a full sized ethash PoW shared between all requesters
-// running in the same process.
-func NewSharedEthash() PoW {
-	return sharedEthash
+// NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts
+// all blocks' seal as valid, though they still have to conform to the Ethereum
+// consensus rules.
+func NewFaker() *Ethash {
+	return &Ethash{fakeMode: true}
 }
 }
 
 
-// Verify implements PoW, checking whether the given block satisfies the PoW
-// difficulty requirements.
-func (ethash *Ethash) Verify(block Block) error {
-	// Sanity check that the block number is below the lookup table size (60M blocks)
-	number := block.NumberU64()
-	if number/epochLength >= uint64(len(cacheSizes)) {
-		// Go < 1.7 cannot calculate new cache/dataset sizes (no fast prime check)
-		return ErrNonceOutOfRange
-	}
-	// Ensure that we have a valid difficulty for the block
-	difficulty := block.Difficulty()
-	if difficulty.Sign() <= 0 {
-		return ErrInvalidDifficulty
-	}
-	// Recompute the digest and PoW value and verify against the block
-	cache := ethash.cache(number)
+// NewFakeFailer creates a ethash consensus engine with a fake PoW scheme that
+// accepts all blocks as valid apart from the single one specified, though they
+// still have to conform to the Ethereum consensus rules.
+func NewFakeFailer(fail uint64) *Ethash {
+	return &Ethash{fakeMode: true, fakeFail: fail}
+}
 
 
-	size := datasetSize(number)
-	if ethash.tester {
-		size = 32 * 1024
-	}
-	digest, result := hashimotoLight(size, cache, block.HashNoNonce().Bytes(), block.Nonce())
-	if !bytes.Equal(block.MixDigest().Bytes(), digest) {
-		return ErrInvalidMixDigest
-	}
-	target := new(big.Int).Div(maxUint256, difficulty)
-	if new(big.Int).SetBytes(result).Cmp(target) > 0 {
-		return ErrInvalidPoW
-	}
-	return nil
+// NewFakeDelayer creates a ethash consensus engine with a fake PoW scheme that
+// accepts all blocks as valid, but delays verifications by some time, though
+// they still have to conform to the Ethereum consensus rules.
+func NewFakeDelayer(delay time.Duration) *Ethash {
+	return &Ethash{fakeMode: true, fakeDelay: delay}
+}
+
+// NewFullFaker creates a ethash consensus engine with a full fake scheme that
+// accepts all blocks as valid, without checking any consensus rules whatsoever.
+func NewFullFaker() *Ethash {
+	return &Ethash{fakeMode: true, fakeFull: true}
+}
+
+// NewShared creates a full sized ethash PoW shared between all requesters running
+// in the same process.
+func NewShared() *Ethash {
+	return &Ethash{shared: sharedEthash}
 }
 }
 
 
 // cache tries to retrieve a verification cache for the specified block number
 // cache tries to retrieve a verification cache for the specified block number
@@ -477,43 +482,6 @@ func (ethash *Ethash) cache(block uint64) []uint32 {
 	return current.cache
 	return current.cache
 }
 }
 
 
-// Search implements PoW, attempting to find a nonce that satisfies the block's
-// difficulty requirements.
-func (ethash *Ethash) Search(block Block, stop <-chan struct{}) (uint64, []byte) {
-	var (
-		hash     = block.HashNoNonce().Bytes()
-		diff     = block.Difficulty()
-		target   = new(big.Int).Div(maxUint256, diff)
-		dataset  = ethash.dataset(block.NumberU64())
-		rand     = rand.New(rand.NewSource(time.Now().UnixNano()))
-		nonce    = uint64(rand.Int63())
-		attempts int64
-	)
-	// Start generating random nonces until we abort or find a good one
-	for {
-		select {
-		case <-stop:
-			// Mining terminated, update stats and abort
-			ethash.hashrate.Mark(attempts)
-			return 0, nil
-
-		default:
-			// We don't have to update hash rate on every nonce, so update after after 2^X nonces
-			attempts++
-			if (attempts % (1 << 15)) == 0 {
-				ethash.hashrate.Mark(attempts)
-				attempts = 0
-			}
-			// Compute the PoW value of this nonce
-			digest, result := hashimotoFull(dataset, hash, nonce)
-			if new(big.Int).SetBytes(result).Cmp(target) <= 0 {
-				return nonce, digest
-			}
-			nonce++
-		}
-	}
-}
-
 // dataset tries to retrieve a mining dataset for the specified block number
 // dataset tries to retrieve a mining dataset for the specified block number
 // by first checking against a list of in-memory datasets, then against DAGs
 // by first checking against a list of in-memory datasets, then against DAGs
 // stored on disk, and finally generating one if none can be found.
 // stored on disk, and finally generating one if none can be found.
@@ -576,14 +544,44 @@ func (ethash *Ethash) dataset(block uint64) []uint32 {
 	return current.dataset
 	return current.dataset
 }
 }
 
 
+// Threads returns the number of mining threads currently enabled. This doesn't
+// necessarily mean that mining is running!
+func (ethash *Ethash) Threads() int {
+	ethash.lock.Lock()
+	defer ethash.lock.Unlock()
+
+	return ethash.threads
+}
+
+// SetThreads updates the number of mining threads currently enabled. Calling
+// this method does not start mining, only sets the thread count. If zero is
+// specified, the miner will use all cores of the machine.
+func (ethash *Ethash) SetThreads(threads int) {
+	ethash.lock.Lock()
+	defer ethash.lock.Unlock()
+
+	// Update the threads and ping any running seal to pull in any changes
+	ethash.threads = threads
+	select {
+	case ethash.update <- struct{}{}:
+	default:
+	}
+}
+
 // Hashrate implements PoW, returning the measured rate of the search invocations
 // Hashrate implements PoW, returning the measured rate of the search invocations
 // per second over the last minute.
 // per second over the last minute.
 func (ethash *Ethash) Hashrate() float64 {
 func (ethash *Ethash) Hashrate() float64 {
 	return ethash.hashrate.Rate1()
 	return ethash.hashrate.Rate1()
 }
 }
 
 
-// EthashSeedHash is the seed to use for generating a vrification cache and the
-// mining dataset.
-func EthashSeedHash(block uint64) []byte {
+// APIs implements consensus.Engine, returning the user facing RPC APIs. Currently
+// that is empty.
+func (ethash *Ethash) APIs(chain consensus.ChainReader) []rpc.API {
+	return nil
+}
+
+// SeedHash is the seed to use for generating a verification cache and the mining
+// dataset.
+func SeedHash(block uint64) []byte {
 	return seedHash(block)
 	return seedHash(block)
 }
 }

+ 40 - 0
consensus/ethash/ethash_test.go

@@ -0,0 +1,40 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package ethash
+
+import (
+	"math/big"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/core/types"
+)
+
+// Tests that ethash works correctly in test mode.
+func TestTestMode(t *testing.T) {
+	head := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)}
+
+	ethash := NewTester()
+	block, err := ethash.Seal(nil, types.NewBlockWithHeader(head), nil)
+	if err != nil {
+		t.Fatalf("failed to seal block: %v", err)
+	}
+	head.Nonce = types.EncodeNonce(block.Nonce())
+	head.MixDigest = block.MixDigest()
+	if err := ethash.VerifySeal(nil, head); err != nil {
+		t.Fatalf("unexpected verification error: %v", err)
+	}
+}

+ 146 - 0
consensus/ethash/sealer.go

@@ -0,0 +1,146 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package ethash
+
+import (
+	crand "crypto/rand"
+	"math"
+	"math/big"
+	"math/rand"
+	"runtime"
+	"sync"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/log"
+)
+
+// Seal implements consensus.Engine, attempting to find a nonce that satisfies
+// the block's difficulty requirements.
+func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) {
+	// If we're running a fake PoW, simply return a 0 nonce immediately
+	if ethash.fakeMode {
+		header := block.Header()
+		header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{}
+		return block.WithSeal(header), nil
+	}
+	// If we're running a shared PoW, delegate sealing to it
+	if ethash.shared != nil {
+		return ethash.shared.Seal(chain, block, stop)
+	}
+	// Create a runner and the multiple search threads it directs
+	abort := make(chan struct{})
+	found := make(chan *types.Block)
+
+	ethash.lock.Lock()
+	threads := ethash.threads
+	if ethash.rand == nil {
+		seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
+		if err != nil {
+			ethash.lock.Unlock()
+			return nil, err
+		}
+		ethash.rand = rand.New(rand.NewSource(seed.Int64()))
+	}
+	ethash.lock.Unlock()
+	if threads == 0 {
+		threads = runtime.NumCPU()
+	}
+	var pend sync.WaitGroup
+	for i := 0; i < threads; i++ {
+		pend.Add(1)
+		go func(id int, nonce uint64) {
+			defer pend.Done()
+			ethash.mine(block, id, nonce, abort, found)
+		}(i, uint64(ethash.rand.Int63()))
+	}
+	// Wait until sealing is terminated or a nonce is found
+	var result *types.Block
+	select {
+	case <-stop:
+		// Outside abort, stop all miner threads
+		close(abort)
+	case result = <-found:
+		// One of the threads found a block, abort all others
+		close(abort)
+	case <-ethash.update:
+		// Thread count was changed on user request, restart
+		close(abort)
+		pend.Wait()
+		return ethash.Seal(chain, block, stop)
+	}
+	// Wait for all miners to terminate and return the block
+	pend.Wait()
+	return result, nil
+}
+
+// mine is the actual proof-of-work miner that searches for a nonce starting from
+// seed that results in correct final block difficulty.
+func (ethash *Ethash) mine(block *types.Block, id int, seed uint64, abort chan struct{}, found chan *types.Block) {
+	// Extract some data from the header
+	var (
+		header = block.Header()
+		hash   = header.HashNoNonce().Bytes()
+		target = new(big.Int).Div(maxUint256, header.Difficulty)
+
+		number  = header.Number.Uint64()
+		dataset = ethash.dataset(number)
+	)
+	// Start generating random nonces until we abort or find a good one
+	var (
+		attempts = int64(0)
+		nonce    = seed
+	)
+	logger := log.New("miner", id)
+	logger.Trace("Started ethash search for new nonces", "seed", seed)
+	for {
+		select {
+		case <-abort:
+			// Mining terminated, update stats and abort
+			logger.Trace("Ethash nonce search aborted", "attempts", nonce-seed)
+			ethash.hashrate.Mark(attempts)
+			return
+
+		default:
+			// We don't have to update hash rate on every nonce, so update after after 2^X nonces
+			attempts++
+			if (attempts % (1 << 15)) == 0 {
+				ethash.hashrate.Mark(attempts)
+				attempts = 0
+			}
+			// Compute the PoW value of this nonce
+			digest, result := hashimotoFull(dataset, hash, nonce)
+			if new(big.Int).SetBytes(result).Cmp(target) <= 0 {
+				// Correct nonce found, create a new header with it
+				header = types.CopyHeader(header)
+				header.Nonce = types.EncodeNonce(nonce)
+				header.MixDigest = common.BytesToHash(digest)
+
+				// Seal and return a block (if still needed)
+				select {
+				case found <- block.WithSeal(header):
+					logger.Trace("Ethash nonce found and reported", "attempts", nonce-seed, "nonce", nonce)
+				case <-abort:
+					logger.Trace("Ethash nonce found but discarded", "attempts", nonce-seed, "nonce", nonce)
+				}
+				return
+			}
+			nonce++
+		}
+	}
+}

+ 1 - 1
pow/xor.go → consensus/ethash/xor.go

@@ -4,7 +4,7 @@
 
 
 // Source: https://golang.org/src/crypto/cipher/xor.go
 // Source: https://golang.org/src/crypto/cipher/xor.go
 
 
-package pow
+package ethash
 
 
 import (
 import (
 	"runtime"
 	"runtime"

+ 85 - 0
consensus/misc/dao.go

@@ -0,0 +1,85 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package misc
+
+import (
+	"bytes"
+	"errors"
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/params"
+)
+
+var (
+	// ErrBadProDAOExtra is returned if a header doens't support the DAO fork on a
+	// pro-fork client.
+	ErrBadProDAOExtra = errors.New("bad DAO pro-fork extra-data")
+
+	// ErrBadNoDAOExtra is returned if a header does support the DAO fork on a no-
+	// fork client.
+	ErrBadNoDAOExtra = errors.New("bad DAO no-fork extra-data")
+)
+
+// VerifyDAOHeaderExtraData validates the extra-data field of a block header to
+// ensure it conforms to DAO hard-fork rules.
+//
+// DAO hard-fork extension to the header validity:
+//   a) if the node is no-fork, do not accept blocks in the [fork, fork+10) range
+//      with the fork specific extra-data set
+//   b) if the node is pro-fork, require blocks in the specific range to have the
+//      unique extra-data set.
+func VerifyDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) error {
+	// Short circuit validation if the node doesn't care about the DAO fork
+	if config.DAOForkBlock == nil {
+		return nil
+	}
+	// Make sure the block is within the fork's modified extra-data range
+	limit := new(big.Int).Add(config.DAOForkBlock, params.DAOForkExtraRange)
+	if header.Number.Cmp(config.DAOForkBlock) < 0 || header.Number.Cmp(limit) >= 0 {
+		return nil
+	}
+	// Depending whether we support or oppose the fork, validate the extra-data contents
+	if config.DAOForkSupport {
+		if !bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
+			return ErrBadProDAOExtra
+		}
+	} else {
+		if bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
+			return ErrBadNoDAOExtra
+		}
+	}
+	// All ok, header has the same extra-data we expect
+	return nil
+}
+
+// ApplyDAOHardFork modifies the state database according to the DAO hard-fork
+// rules, transferring all balances of a set of DAO accounts to a single refund
+// contract.
+func ApplyDAOHardFork(statedb *state.StateDB) {
+	// Retrieve the contract to refund balances into
+	if !statedb.Exist(params.DAORefundContract) {
+		statedb.CreateAccount(params.DAORefundContract)
+	}
+
+	// Move every DAO account and extra-balance account funds into the refund contract
+	for _, addr := range params.DAODrainList() {
+		statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
+		statedb.SetBalance(addr, new(big.Int))
+	}
+}

+ 43 - 0
consensus/misc/forks.go

@@ -0,0 +1,43 @@
+// Copyright 2017 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package misc
+
+import (
+	"fmt"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/params"
+)
+
+// VerifyForkHashes verifies that blocks conforming to network hard-forks do have
+// the correct hashes, to avoid clients going off on different chains. This is an
+// optional feature.
+func VerifyForkHashes(config *params.ChainConfig, header *types.Header, uncle bool) error {
+	// We don't care about uncles
+	if uncle {
+		return nil
+	}
+	// If the homestead reprice hash is set, validate it
+	if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 {
+		if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() {
+			return fmt.Errorf("homestead gas reprice fork: have 0x%x, want 0x%x", header.Hash(), config.EIP150Hash)
+		}
+	}
+	// All ok, return
+	return nil
+}

+ 3 - 3
core/bench_test.go

@@ -25,13 +25,13 @@ import (
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 func BenchmarkInsertChain_empty_memdb(b *testing.B) {
 func BenchmarkInsertChain_empty_memdb(b *testing.B) {
@@ -176,7 +176,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
 	// Time the insertion of the new chain.
 	// Time the insertion of the new chain.
 	// State and blocks are stored in the same DB.
 	// State and blocks are stored in the same DB.
 	evmux := new(event.TypeMux)
 	evmux := new(event.TypeMux)
-	chainman, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
+	chainman, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), evmux, vm.Config{})
 	defer chainman.Stop()
 	defer chainman.Stop()
 	b.ReportAllocs()
 	b.ReportAllocs()
 	b.ResetTimer()
 	b.ResetTimer()
@@ -286,7 +286,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
 		if err != nil {
 		if err != nil {
 			b.Fatalf("error opening database at %v: %v", dir, err)
 			b.Fatalf("error opening database at %v: %v", dir, err)
 		}
 		}
-		chain, err := NewBlockChain(db, params.TestChainConfig, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+		chain, err := NewBlockChain(db, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 		if err != nil {
 		if err != nil {
 			b.Fatalf("error creating chain: %v", err)
 			b.Fatalf("error creating chain: %v", err)
 		}
 		}

+ 15 - 260
core/block_validator.go

@@ -19,22 +19,12 @@ package core
 import (
 import (
 	"fmt"
 	"fmt"
 	"math/big"
 	"math/big"
-	"time"
 
 
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
-	"gopkg.in/fatih/set.v0"
-)
-
-var (
-	ExpDiffPeriod = big.NewInt(100000)
-	big10         = big.NewInt(10)
-	bigMinus99    = big.NewInt(-99)
 )
 )
 
 
 // BlockValidator is responsible for validating block headers, uncles and
 // BlockValidator is responsible for validating block headers, uncles and
@@ -44,30 +34,24 @@ var (
 type BlockValidator struct {
 type BlockValidator struct {
 	config *params.ChainConfig // Chain configuration options
 	config *params.ChainConfig // Chain configuration options
 	bc     *BlockChain         // Canonical block chain
 	bc     *BlockChain         // Canonical block chain
-	Pow    pow.PoW             // Proof of work used for validating
+	engine consensus.Engine    // Consensus engine used for validating
 }
 }
 
 
 // NewBlockValidator returns a new block validator which is safe for re-use
 // NewBlockValidator returns a new block validator which is safe for re-use
-func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator {
+func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
 	validator := &BlockValidator{
 	validator := &BlockValidator{
 		config: config,
 		config: config,
-		Pow:    pow,
+		engine: engine,
 		bc:     blockchain,
 		bc:     blockchain,
 	}
 	}
 	return validator
 	return validator
 }
 }
 
 
-// ValidateBlock validates the given block's header and uncles and verifies the
-// the block header's transaction and uncle roots.
-//
-// ValidateBlock does not validate the header's pow. The pow work validated
-// separately so we can process them in parallel.
-//
-// ValidateBlock also validates and makes sure that any previous state (or present)
-// state that might or might not be present is checked to make sure that fast
-// sync has done it's job proper. This prevents the block validator from accepting
-// false positives where a header is present but the state is not.
-func (v *BlockValidator) ValidateBlock(block *types.Block) error {
+// ValidateBody validates the given block's uncles and verifies the the block
+// header's transaction and uncle roots. The headers are assumed to be already
+// validated at this point.
+func (v *BlockValidator) ValidateBody(block *types.Block) error {
+	// Check whether the block's known, and if not, that it's linkable
 	if v.bc.HasBlock(block.Hash()) {
 	if v.bc.HasBlock(block.Hash()) {
 		if _, err := state.New(block.Root(), v.bc.chainDb); err == nil {
 		if _, err := state.New(block.Root(), v.bc.chainDb); err == nil {
 			return &KnownBlockError{block.Number(), block.Hash()}
 			return &KnownBlockError{block.Number(), block.Hash()}
@@ -80,30 +64,17 @@ func (v *BlockValidator) ValidateBlock(block *types.Block) error {
 	if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil {
 	if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil {
 		return ParentError(block.ParentHash())
 		return ParentError(block.ParentHash())
 	}
 	}
-
+	// Header validity is known at this point, check the uncles and transactions
 	header := block.Header()
 	header := block.Header()
-	// validate the block header
-	if err := ValidateHeader(v.config, v.Pow, header, parent.Header(), false, false); err != nil {
+	if err := v.engine.VerifyUncles(v.bc, block); err != nil {
 		return err
 		return err
 	}
 	}
-	// verify the uncles are correctly rewarded
-	if err := v.VerifyUncles(block, parent); err != nil {
-		return err
+	if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
+		return fmt.Errorf("uncle root hash mismatch: have %x, want %x", hash, header.UncleHash)
 	}
 	}
-
-	// Verify UncleHash before running other uncle validations
-	unclesSha := types.CalcUncleHash(block.Uncles())
-	if unclesSha != header.UncleHash {
-		return fmt.Errorf("invalid uncles root hash (remote: %x local: %x)", header.UncleHash, unclesSha)
-	}
-
-	// The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
-	// can be used by light clients to make sure they've received the correct Txs
-	txSha := types.DeriveSha(block.Transactions())
-	if txSha != header.TxHash {
-		return fmt.Errorf("invalid transaction root hash (remote: %x local: %x)", header.TxHash, txSha)
+	if hash := types.DeriveSha(block.Transactions()); hash != header.TxHash {
+		return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
 	}
 	}
-
 	return nil
 	return nil
 }
 }
 
 
@@ -135,222 +106,6 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
 	return nil
 	return nil
 }
 }
 
 
-// VerifyUncles verifies the given block's uncles and applies the Ethereum
-// consensus rules to the various block headers included; it will return an
-// error if any of the included uncle headers were invalid. It returns an error
-// if the validation failed.
-func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error {
-	// validate that there are at most 2 uncles included in this block
-	if len(block.Uncles()) > 2 {
-		return ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles()))
-	}
-
-	uncles := set.New()
-	ancestors := make(map[common.Hash]*types.Block)
-	for _, ancestor := range v.bc.GetBlocksFromHash(block.ParentHash(), 7) {
-		ancestors[ancestor.Hash()] = ancestor
-		// Include ancestors uncles in the uncle set. Uncles must be unique.
-		for _, uncle := range ancestor.Uncles() {
-			uncles.Add(uncle.Hash())
-		}
-	}
-	ancestors[block.Hash()] = block
-	uncles.Add(block.Hash())
-
-	for i, uncle := range block.Uncles() {
-		hash := uncle.Hash()
-		if uncles.Has(hash) {
-			// Error not unique
-			return UncleError("uncle[%d](%x) not unique", i, hash[:4])
-		}
-		uncles.Add(hash)
-
-		if ancestors[hash] != nil {
-			branch := fmt.Sprintf("  O - %x\n  |\n", block.Hash())
-			for h := range ancestors {
-				branch += fmt.Sprintf("  O - %x\n  |\n", h)
-			}
-			log.Warn(branch)
-			return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
-		}
-
-		if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == parent.Hash() {
-			return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4])
-		}
-
-		if err := ValidateHeader(v.config, v.Pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil {
-			return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
-		}
-	}
-
-	return nil
-}
-
-// ValidateHeader validates the given header and, depending on the pow arg,
-// checks the proof of work of the given header. Returns an error if the
-// validation failed.
-func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow bool) error {
-	// Short circuit if the parent is missing.
-	if parent == nil {
-		return ParentError(header.ParentHash)
-	}
-	// Short circuit if the header's already known or its parent is missing
-	if v.bc.HasHeader(header.Hash()) {
-		return nil
-	}
-	return ValidateHeader(v.config, v.Pow, header, parent, checkPow, false)
-}
-
-// Validates a header. Returns an error if the header is invalid.
-//
-// See YP section 4.3.4. "Block Header Validity"
-func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
-	if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
-		return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
-	}
-
-	if uncle {
-		if header.Time.Cmp(math.MaxBig256) == 1 {
-			return BlockTSTooBigErr
-		}
-	} else {
-		if header.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 {
-			return BlockFutureErr
-		}
-	}
-	if header.Time.Cmp(parent.Time) != 1 {
-		return BlockEqualTSErr
-	}
-
-	expd := CalcDifficulty(config, header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty)
-	if expd.Cmp(header.Difficulty) != 0 {
-		return fmt.Errorf("Difficulty check failed for header (remote: %v local: %v)", header.Difficulty, expd)
-	}
-
-	a := new(big.Int).Set(parent.GasLimit)
-	a = a.Sub(a, header.GasLimit)
-	a.Abs(a)
-	b := new(big.Int).Set(parent.GasLimit)
-	b = b.Div(b, params.GasLimitBoundDivisor)
-	if !(a.Cmp(b) < 0) || (header.GasLimit.Cmp(params.MinGasLimit) == -1) {
-		return fmt.Errorf("GasLimit check failed for header (remote: %v local_max: %v)", header.GasLimit, b)
-	}
-
-	num := new(big.Int).Set(parent.Number)
-	num.Sub(header.Number, num)
-	if num.Cmp(big.NewInt(1)) != 0 {
-		return BlockNumberErr
-	}
-
-	if checkPow {
-		// Verify the nonce of the header. Return an error if it's not valid
-		if err := pow.Verify(types.NewBlockWithHeader(header)); err != nil {
-			return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()}
-		}
-	}
-	// If all checks passed, validate the extra-data field for hard forks
-	if err := ValidateDAOHeaderExtraData(config, header); err != nil {
-		return err
-	}
-	if !uncle && config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 {
-		if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() {
-			return ValidationError("Homestead gas reprice fork hash mismatch: have 0x%x, want 0x%x", header.Hash(), config.EIP150Hash)
-		}
-	}
-	return nil
-}
-
-// CalcDifficulty is the difficulty adjustment algorithm. It returns
-// the difficulty that a new block should have when created at time
-// given the parent block's time and difficulty.
-func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
-	if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
-		return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
-	} else {
-		return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff)
-	}
-}
-
-func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
-	// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki
-	// algorithm:
-	// diff = (parent_diff +
-	//         (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
-	//        ) + 2^(periodCount - 2)
-
-	bigTime := new(big.Int).SetUint64(time)
-	bigParentTime := new(big.Int).SetUint64(parentTime)
-
-	// holds intermediate values to make the algo easier to read & audit
-	x := new(big.Int)
-	y := new(big.Int)
-
-	// 1 - (block_timestamp -parent_timestamp) // 10
-	x.Sub(bigTime, bigParentTime)
-	x.Div(x, big10)
-	x.Sub(common.Big1, x)
-
-	// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
-	if x.Cmp(bigMinus99) < 0 {
-		x.Set(bigMinus99)
-	}
-
-	// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
-	y.Div(parentDiff, params.DifficultyBoundDivisor)
-	x.Mul(y, x)
-	x.Add(parentDiff, x)
-
-	// minimum difficulty can ever be (before exponential factor)
-	if x.Cmp(params.MinimumDifficulty) < 0 {
-		x.Set(params.MinimumDifficulty)
-	}
-
-	// for the exponential factor
-	periodCount := new(big.Int).Add(parentNumber, common.Big1)
-	periodCount.Div(periodCount, ExpDiffPeriod)
-
-	// the exponential factor, commonly referred to as "the bomb"
-	// diff = diff + 2^(periodCount - 2)
-	if periodCount.Cmp(common.Big1) > 0 {
-		y.Sub(periodCount, common.Big2)
-		y.Exp(common.Big2, y, nil)
-		x.Add(x, y)
-	}
-
-	return x
-}
-
-func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
-	diff := new(big.Int)
-	adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor)
-	bigTime := new(big.Int)
-	bigParentTime := new(big.Int)
-
-	bigTime.SetUint64(time)
-	bigParentTime.SetUint64(parentTime)
-
-	if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 {
-		diff.Add(parentDiff, adjust)
-	} else {
-		diff.Sub(parentDiff, adjust)
-	}
-	if diff.Cmp(params.MinimumDifficulty) < 0 {
-		diff.Set(params.MinimumDifficulty)
-	}
-
-	periodCount := new(big.Int).Add(parentNumber, common.Big1)
-	periodCount.Div(periodCount, ExpDiffPeriod)
-	if periodCount.Cmp(common.Big1) > 0 {
-		// diff = diff + 2^(periodCount - 2)
-		expDiff := periodCount.Sub(periodCount, common.Big2)
-		expDiff.Exp(common.Big2, expDiff, nil)
-		diff.Add(diff, expDiff)
-		diff = math.BigMax(diff, params.MinimumDifficulty)
-	}
-
-	return diff
-}
-
 // CalcGasLimit computes the gas limit of the next block after parent.
 // CalcGasLimit computes the gas limit of the next block after parent.
 // The result may be modified by the caller.
 // The result may be modified by the caller.
 // This is miner strategy, not consensus protocol.
 // This is miner strategy, not consensus protocol.

+ 159 - 44
core/block_validator_test.go

@@ -17,64 +17,179 @@
 package core
 package core
 
 
 import (
 import (
-	"math/big"
+	"runtime"
 	"testing"
 	"testing"
+	"time"
 
 
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
+	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
-func testGenesis(account common.Address, balance *big.Int) *Genesis {
-	return &Genesis{
-		Config: params.TestChainConfig,
-		Alloc:  GenesisAlloc{account: {Balance: balance}},
+// Tests that simple header verification works, for both good and bad blocks.
+func TestHeaderVerification(t *testing.T) {
+	// Create a simple chain to verify
+	var (
+		testdb, _ = ethdb.NewMemDatabase()
+		gspec     = &Genesis{Config: params.TestChainConfig}
+		genesis   = gspec.MustCommit(testdb)
+		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
+	)
+	headers := make([]*types.Header, len(blocks))
+	for i, block := range blocks {
+		headers[i] = block.Header()
+	}
+	// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
+	chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
+
+	for i := 0; i < len(blocks); i++ {
+		for j, valid := range []bool{true, false} {
+			var results <-chan error
+
+			if valid {
+				engine := ethash.NewFaker()
+				_, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true})
+			} else {
+				engine := ethash.NewFakeFailer(headers[i].Number.Uint64())
+				_, results = engine.VerifyHeaders(chain, []*types.Header{headers[i]}, []bool{true})
+			}
+			// Wait for the verification result
+			select {
+			case result := <-results:
+				if (result == nil) != valid {
+					t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, result, valid)
+				}
+			case <-time.After(time.Second):
+				t.Fatalf("test %d.%d: verification timeout", i, j)
+			}
+			// Make sure no more data is returned
+			select {
+			case result := <-results:
+				t.Fatalf("test %d.%d: unexpected result returned: %v", i, j, result)
+			case <-time.After(25 * time.Millisecond):
+			}
+		}
+		chain.InsertChain(blocks[i : i+1])
 	}
 	}
 }
 }
 
 
-func TestNumber(t *testing.T) {
-	chain := newTestBlockChain()
-	statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
-	header := makeHeader(chain.config, chain.Genesis(), statedb)
-	header.Number = big.NewInt(3)
-	err := ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
-	if err != BlockNumberErr {
-		t.Errorf("expected block number error, got %q", err)
+// Tests that concurrent header verification works, for both good and bad blocks.
+func TestHeaderConcurrentVerification2(t *testing.T)  { testHeaderConcurrentVerification(t, 2) }
+func TestHeaderConcurrentVerification8(t *testing.T)  { testHeaderConcurrentVerification(t, 8) }
+func TestHeaderConcurrentVerification32(t *testing.T) { testHeaderConcurrentVerification(t, 32) }
+
+func testHeaderConcurrentVerification(t *testing.T, threads int) {
+	// Create a simple chain to verify
+	var (
+		testdb, _ = ethdb.NewMemDatabase()
+		gspec     = &Genesis{Config: params.TestChainConfig}
+		genesis   = gspec.MustCommit(testdb)
+		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
+	)
+	headers := make([]*types.Header, len(blocks))
+	seals := make([]bool, len(blocks))
+
+	for i, block := range blocks {
+		headers[i] = block.Header()
+		seals[i] = true
 	}
 	}
+	// Set the number of threads to verify on
+	old := runtime.GOMAXPROCS(threads)
+	defer runtime.GOMAXPROCS(old)
+
+	// Run the header checker for the entire block chain at once both for a valid and
+	// also an invalid chain (enough if one arbitrary block is invalid).
+	for i, valid := range []bool{true, false} {
+		var results <-chan error
+
+		if valid {
+			chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
+			_, results = chain.engine.VerifyHeaders(chain, headers, seals)
+		} else {
+			chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), new(event.TypeMux), vm.Config{})
+			_, results = chain.engine.VerifyHeaders(chain, headers, seals)
+		}
+		// Wait for all the verification results
+		checks := make(map[int]error)
+		for j := 0; j < len(blocks); j++ {
+			select {
+			case result := <-results:
+				checks[j] = result
 
 
-	header = makeHeader(chain.config, chain.Genesis(), statedb)
-	err = ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
-	if err == BlockNumberErr {
-		t.Errorf("didn't expect block number error")
+			case <-time.After(time.Second):
+				t.Fatalf("test %d.%d: verification timeout", i, j)
+			}
+		}
+		// Check nonce check validity
+		for j := 0; j < len(blocks); j++ {
+			want := valid || (j < len(blocks)-2) // We chose the last-but-one nonce in the chain to fail
+			if (checks[j] == nil) != want {
+				t.Errorf("test %d.%d: validity mismatch: have %v, want %v", i, j, checks[j], want)
+			}
+			if !want {
+				// A few blocks after the first error may pass verification due to concurrent
+				// workers. We don't care about those in this test, just that the correct block
+				// errors out.
+				break
+			}
+		}
+		// Make sure no more data is returned
+		select {
+		case result := <-results:
+			t.Fatalf("test %d: unexpected result returned: %v", i, result)
+		case <-time.After(25 * time.Millisecond):
+		}
 	}
 	}
 }
 }
 
 
-func TestPutReceipt(t *testing.T) {
-	db, _ := ethdb.NewMemDatabase()
-
-	var addr common.Address
-	addr[0] = 1
-	var hash common.Hash
-	hash[0] = 2
-
-	receipt := new(types.Receipt)
-	receipt.Logs = []*types.Log{{
-		Address:     addr,
-		Topics:      []common.Hash{hash},
-		Data:        []byte("hi"),
-		BlockNumber: 42,
-		TxHash:      hash,
-		TxIndex:     0,
-		BlockHash:   hash,
-		Index:       0,
-	}}
-
-	WriteReceipts(db, types.Receipts{receipt})
-	receipt = GetReceipt(db, common.Hash{})
-	if receipt == nil {
-		t.Error("expected to get 1 receipt, got none.")
+// Tests that aborting a header validation indeed prevents further checks from being
+// run, as well as checks that no left-over goroutines are leaked.
+func TestHeaderConcurrentAbortion2(t *testing.T)  { testHeaderConcurrentAbortion(t, 2) }
+func TestHeaderConcurrentAbortion8(t *testing.T)  { testHeaderConcurrentAbortion(t, 8) }
+func TestHeaderConcurrentAbortion32(t *testing.T) { testHeaderConcurrentAbortion(t, 32) }
+
+func testHeaderConcurrentAbortion(t *testing.T, threads int) {
+	// Create a simple chain to verify
+	var (
+		testdb, _ = ethdb.NewMemDatabase()
+		gspec     = &Genesis{Config: params.TestChainConfig}
+		genesis   = gspec.MustCommit(testdb)
+		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 1024, nil)
+	)
+	headers := make([]*types.Header, len(blocks))
+	seals := make([]bool, len(blocks))
+
+	for i, block := range blocks {
+		headers[i] = block.Header()
+		seals[i] = true
+	}
+	// Set the number of threads to verify on
+	old := runtime.GOMAXPROCS(threads)
+	defer runtime.GOMAXPROCS(old)
+
+	// Start the verifications and immediately abort
+	chain, _ := NewBlockChain(testdb, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), new(event.TypeMux), vm.Config{})
+	abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
+	close(abort)
+
+	// Deplete the results channel
+	verified := 0
+	for depleted := false; !depleted; {
+		select {
+		case result := <-results:
+			if result != nil {
+				t.Errorf("header %d: validation failed: %v", verified, result)
+			}
+			verified++
+		case <-time.After(50 * time.Millisecond):
+			depleted = true
+		}
+	}
+	// Check that abortion was honored by not processing too many POWs
+	if verified > 2*threads {
+		t.Errorf("verification count too large: have %d, want below %d", verified, 2*threads)
 	}
 	}
 }
 }

+ 26 - 36
core/blockchain.go

@@ -30,6 +30,7 @@ import (
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/mclock"
 	"github.com/ethereum/go-ethereum/common/mclock"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
@@ -39,7 +40,6 @@ import (
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/metrics"
 	"github.com/ethereum/go-ethereum/metrics"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/trie"
 	"github.com/ethereum/go-ethereum/trie"
 	"github.com/hashicorp/golang-lru"
 	"github.com/hashicorp/golang-lru"
@@ -104,7 +104,7 @@ type BlockChain struct {
 	procInterrupt int32          // interrupt signaler for block processing
 	procInterrupt int32          // interrupt signaler for block processing
 	wg            sync.WaitGroup // chain processing wait group for shutting down
 	wg            sync.WaitGroup // chain processing wait group for shutting down
 
 
-	pow       pow.PoW
+	engine    consensus.Engine
 	processor Processor // block processor interface
 	processor Processor // block processor interface
 	validator Validator // block and state validator interface
 	validator Validator // block and state validator interface
 	vmConfig  vm.Config
 	vmConfig  vm.Config
@@ -115,7 +115,7 @@ type BlockChain struct {
 // NewBlockChain returns a fully initialised block chain using information
 // NewBlockChain returns a fully initialised block chain using information
 // available in the database. It initialiser the default Ethereum Validator and
 // available in the database. It initialiser the default Ethereum Validator and
 // Processor.
 // Processor.
-func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.PoW, mux *event.TypeMux, vmConfig vm.Config) (*BlockChain, error) {
+func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, mux *event.TypeMux, vmConfig vm.Config) (*BlockChain, error) {
 	bodyCache, _ := lru.New(bodyCacheLimit)
 	bodyCache, _ := lru.New(bodyCacheLimit)
 	bodyRLPCache, _ := lru.New(bodyCacheLimit)
 	bodyRLPCache, _ := lru.New(bodyCacheLimit)
 	blockCache, _ := lru.New(blockCacheLimit)
 	blockCache, _ := lru.New(blockCacheLimit)
@@ -131,25 +131,22 @@ func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.P
 		bodyRLPCache: bodyRLPCache,
 		bodyRLPCache: bodyRLPCache,
 		blockCache:   blockCache,
 		blockCache:   blockCache,
 		futureBlocks: futureBlocks,
 		futureBlocks: futureBlocks,
-		pow:          pow,
+		engine:       engine,
 		vmConfig:     vmConfig,
 		vmConfig:     vmConfig,
 		badBlocks:    badBlocks,
 		badBlocks:    badBlocks,
 	}
 	}
-	bc.SetValidator(NewBlockValidator(config, bc, pow))
-	bc.SetProcessor(NewStateProcessor(config, bc))
+	bc.SetValidator(NewBlockValidator(config, bc, engine))
+	bc.SetProcessor(NewStateProcessor(config, bc, engine))
 
 
-	gv := func() HeaderValidator { return bc.Validator() }
 	var err error
 	var err error
-	bc.hc, err = NewHeaderChain(chainDb, config, gv, bc.getProcInterrupt)
+	bc.hc, err = NewHeaderChain(chainDb, config, engine, bc.getProcInterrupt)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-
 	bc.genesisBlock = bc.GetBlockByNumber(0)
 	bc.genesisBlock = bc.GetBlockByNumber(0)
 	if bc.genesisBlock == nil {
 	if bc.genesisBlock == nil {
 		return nil, ErrNoGenesis
 		return nil, ErrNoGenesis
 	}
 	}
-
 	if err := bc.loadLastState(); err != nil {
 	if err := bc.loadLastState(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -233,9 +230,6 @@ func (self *BlockChain) loadLastState() error {
 	log.Info("Loaded most recent local full block", "number", self.currentBlock.Number(), "hash", self.currentBlock.Hash(), "td", blockTd)
 	log.Info("Loaded most recent local full block", "number", self.currentBlock.Number(), "hash", self.currentBlock.Hash(), "td", blockTd)
 	log.Info("Loaded most recent local fast block", "number", self.currentFastBlock.Number(), "hash", self.currentFastBlock.Hash(), "td", fastTd)
 	log.Info("Loaded most recent local fast block", "number", self.currentFastBlock.Number(), "hash", self.currentFastBlock.Hash(), "td", fastTd)
 
 
-	// Try to be smart and issue a pow verification for the head to pre-generate caches
-	go self.pow.Verify(types.NewBlockWithHeader(currentHeader))
-
 	return nil
 	return nil
 }
 }
 
 
@@ -383,9 +377,6 @@ func (self *BlockChain) Processor() Processor {
 	return self.processor
 	return self.processor
 }
 }
 
 
-// AuxValidator returns the auxiliary validator (Proof of work atm)
-func (self *BlockChain) AuxValidator() pow.PoW { return self.pow }
-
 // State returns a new mutable state based on the current HEAD block.
 // State returns a new mutable state based on the current HEAD block.
 func (self *BlockChain) State() (*state.StateDB, error) {
 func (self *BlockChain) State() (*state.StateDB, error) {
 	return self.StateAt(self.CurrentBlock().Root())
 	return self.StateAt(self.CurrentBlock().Root())
@@ -906,38 +897,38 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 		stats         = insertStats{startTime: mclock.Now()}
 		stats         = insertStats{startTime: mclock.Now()}
 		events        = make([]interface{}, 0, len(chain))
 		events        = make([]interface{}, 0, len(chain))
 		coalescedLogs []*types.Log
 		coalescedLogs []*types.Log
-		nonceChecked  = make([]bool, len(chain))
 	)
 	)
+	// Start the parallel header verifier
+	headers := make([]*types.Header, len(chain))
+	seals := make([]bool, len(chain))
 
 
-	// Start the parallel nonce verifier.
-	nonceAbort, nonceResults := verifyNoncesFromBlocks(self.pow, chain)
-	defer close(nonceAbort)
+	for i, block := range chain {
+		headers[i] = block.Header()
+		seals[i] = true
+	}
+	abort, results := self.engine.VerifyHeaders(self, headers, seals)
+	defer close(abort)
 
 
+	// Iterate over the blocks and insert when the verifier permits
 	for i, block := range chain {
 	for i, block := range chain {
+		// If the chain is terminating, stop processing blocks
 		if atomic.LoadInt32(&self.procInterrupt) == 1 {
 		if atomic.LoadInt32(&self.procInterrupt) == 1 {
 			log.Debug("Premature abort during blocks processing")
 			log.Debug("Premature abort during blocks processing")
 			break
 			break
 		}
 		}
-		bstart := time.Now()
-		// Wait for block i's nonce to be verified before processing
-		// its state transition.
-		for !nonceChecked[i] {
-			r := <-nonceResults
-			nonceChecked[r.index] = true
-			if !r.valid {
-				invalid := chain[r.index]
-				return r.index, &BlockNonceErr{Hash: invalid.Hash(), Number: invalid.Number(), Nonce: invalid.Nonce()}
-			}
-		}
-
+		// If the header is a banned one, straight out abort
 		if BadHashes[block.Hash()] {
 		if BadHashes[block.Hash()] {
 			err := BadHashError(block.Hash())
 			err := BadHashError(block.Hash())
 			self.reportBlock(block, nil, err)
 			self.reportBlock(block, nil, err)
 			return i, err
 			return i, err
 		}
 		}
-		// Stage 1 validation of the block using the chain's validator
-		// interface.
-		err := self.Validator().ValidateBlock(block)
+		// Wait for the block's verification to complete
+		bstart := time.Now()
+
+		err := <-results
+		if err == nil {
+			err = self.Validator().ValidateBody(block)
+		}
 		if err != nil {
 		if err != nil {
 			if IsKnownBlockErr(err) {
 			if IsKnownBlockErr(err) {
 				stats.ignored++
 				stats.ignored++
@@ -952,7 +943,6 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 				if block.Time().Cmp(max) == 1 {
 				if block.Time().Cmp(max) == 1 {
 					return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max)
 					return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max)
 				}
 				}
-
 				self.futureBlocks.Add(block.Hash(), block)
 				self.futureBlocks.Add(block.Hash(), block)
 				stats.queued++
 				stats.queued++
 				continue
 				continue

+ 48 - 49
core/blockchain_test.go

@@ -24,6 +24,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
@@ -31,18 +32,21 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 // newTestBlockChain creates a blockchain without validation.
 // newTestBlockChain creates a blockchain without validation.
-func newTestBlockChain() *BlockChain {
+func newTestBlockChain(fake bool) *BlockChain {
 	db, _ := ethdb.NewMemDatabase()
 	db, _ := ethdb.NewMemDatabase()
 	gspec := &Genesis{
 	gspec := &Genesis{
 		Config:     params.TestChainConfig,
 		Config:     params.TestChainConfig,
 		Difficulty: big.NewInt(1),
 		Difficulty: big.NewInt(1),
 	}
 	}
 	gspec.MustCommit(db)
 	gspec.MustCommit(db)
-	blockchain, err := NewBlockChain(db, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	engine := ethash.NewFullFaker()
+	if !fake {
+		engine = ethash.NewTester()
+	}
+	blockchain, err := NewBlockChain(db, gspec.Config, engine, new(event.TypeMux), vm.Config{})
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
@@ -117,7 +121,10 @@ func printChain(bc *BlockChain) {
 func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
 func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
 	for _, block := range chain {
 	for _, block := range chain {
 		// Try and process the block
 		// Try and process the block
-		err := blockchain.Validator().ValidateBlock(block)
+		err := blockchain.engine.VerifyHeader(blockchain, block.Header(), true)
+		if err == nil {
+			err = blockchain.validator.ValidateBody(block)
+		}
 		if err != nil {
 		if err != nil {
 			if IsKnownBlockErr(err) {
 			if IsKnownBlockErr(err) {
 				continue
 				continue
@@ -133,7 +140,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
 			blockchain.reportBlock(block, receipts, err)
 			blockchain.reportBlock(block, receipts, err)
 			return err
 			return err
 		}
 		}
-		err = blockchain.Validator().ValidateState(block, blockchain.GetBlockByHash(block.ParentHash()), statedb, receipts, usedGas)
+		err = blockchain.validator.ValidateState(block, blockchain.GetBlockByHash(block.ParentHash()), statedb, receipts, usedGas)
 		if err != nil {
 		if err != nil {
 			blockchain.reportBlock(block, receipts, err)
 			blockchain.reportBlock(block, receipts, err)
 			return err
 			return err
@@ -152,7 +159,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
 func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error {
 func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error {
 	for _, header := range chain {
 	for _, header := range chain {
 		// Try and validate the header
 		// Try and validate the header
-		if err := blockchain.Validator().ValidateHeader(header, blockchain.GetHeaderByHash(header.ParentHash), false); err != nil {
+		if err := blockchain.engine.VerifyHeader(blockchain, header, false); err != nil {
 			return err
 			return err
 		}
 		}
 		// Manually insert the header into the database, but don't reorganise (allows subsequent testing)
 		// Manually insert the header into the database, but don't reorganise (allows subsequent testing)
@@ -174,7 +181,7 @@ func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *
 }
 }
 
 
 func TestLastBlock(t *testing.T) {
 func TestLastBlock(t *testing.T) {
-	bchain := newTestBlockChain()
+	bchain := newTestBlockChain(false)
 	block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0]
 	block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0]
 	bchain.insert(block)
 	bchain.insert(block)
 	if block.Hash() != GetHeadBlockHash(bchain.chainDb) {
 	if block.Hash() != GetHeadBlockHash(bchain.chainDb) {
@@ -318,8 +325,7 @@ func testBrokenChain(t *testing.T, full bool) {
 
 
 type bproc struct{}
 type bproc struct{}
 
 
-func (bproc) ValidateBlock(*types.Block) error                        { return nil }
-func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return nil }
+func (bproc) ValidateBody(*types.Block) error { return nil }
 func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
 func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
 	return nil
 	return nil
 }
 }
@@ -378,7 +384,7 @@ func testReorgShort(t *testing.T, full bool) {
 }
 }
 
 
 func testReorg(t *testing.T, first, second []int, td int64, full bool) {
 func testReorg(t *testing.T, first, second []int, td int64, full bool) {
-	bc := newTestBlockChain()
+	bc := newTestBlockChain(true)
 
 
 	// Insert an easy and a difficult chain afterwards
 	// Insert an easy and a difficult chain afterwards
 	if full {
 	if full {
@@ -422,7 +428,7 @@ func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) }
 func TestBadBlockHashes(t *testing.T)  { testBadHashes(t, true) }
 func TestBadBlockHashes(t *testing.T)  { testBadHashes(t, true) }
 
 
 func testBadHashes(t *testing.T, full bool) {
 func testBadHashes(t *testing.T, full bool) {
-	bc := newTestBlockChain()
+	bc := newTestBlockChain(true)
 
 
 	// Create a chain, ban a hash and try to import
 	// Create a chain, ban a hash and try to import
 	var err error
 	var err error
@@ -446,7 +452,7 @@ func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) }
 func TestReorgBadBlockHashes(t *testing.T)  { testReorgBadHashes(t, true) }
 func TestReorgBadBlockHashes(t *testing.T)  { testReorgBadHashes(t, true) }
 
 
 func testReorgBadHashes(t *testing.T, full bool) {
 func testReorgBadHashes(t *testing.T, full bool) {
-	bc := newTestBlockChain()
+	bc := newTestBlockChain(true)
 
 
 	// Create a chain, import and ban afterwards
 	// Create a chain, import and ban afterwards
 	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
 	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
@@ -473,7 +479,7 @@ func testReorgBadHashes(t *testing.T, full bool) {
 	}
 	}
 
 
 	// Create a new BlockChain and check that it rolled back the state.
 	// Create a new BlockChain and check that it rolled back the state.
-	ncm, err := NewBlockChain(bc.chainDb, bc.config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	ncm, err := NewBlockChain(bc.chainDb, bc.config, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 	if err != nil {
 	if err != nil {
 		t.Fatalf("failed to create new chain manager: %v", err)
 		t.Fatalf("failed to create new chain manager: %v", err)
 	}
 	}
@@ -504,46 +510,34 @@ func testInsertNonceError(t *testing.T, full bool) {
 		}
 		}
 		// Create and insert a chain with a failing nonce
 		// Create and insert a chain with a failing nonce
 		var (
 		var (
-			failAt   int
-			failRes  int
-			failNum  uint64
-			failHash common.Hash
+			failAt  int
+			failRes int
+			failNum uint64
 		)
 		)
 		if full {
 		if full {
 			blocks := makeBlockChain(blockchain.CurrentBlock(), i, db, 0)
 			blocks := makeBlockChain(blockchain.CurrentBlock(), i, db, 0)
 
 
 			failAt = rand.Int() % len(blocks)
 			failAt = rand.Int() % len(blocks)
 			failNum = blocks[failAt].NumberU64()
 			failNum = blocks[failAt].NumberU64()
-			failHash = blocks[failAt].Hash()
-
-			blockchain.pow = failPow{failNum}
 
 
+			blockchain.engine = ethash.NewFakeFailer(failNum)
 			failRes, err = blockchain.InsertChain(blocks)
 			failRes, err = blockchain.InsertChain(blocks)
 		} else {
 		} else {
 			headers := makeHeaderChain(blockchain.CurrentHeader(), i, db, 0)
 			headers := makeHeaderChain(blockchain.CurrentHeader(), i, db, 0)
 
 
 			failAt = rand.Int() % len(headers)
 			failAt = rand.Int() % len(headers)
 			failNum = headers[failAt].Number.Uint64()
 			failNum = headers[failAt].Number.Uint64()
-			failHash = headers[failAt].Hash()
-
-			blockchain.pow = failPow{failNum}
-			blockchain.validator = NewBlockValidator(params.TestChainConfig, blockchain, failPow{failNum})
 
 
+			blockchain.engine = ethash.NewFakeFailer(failNum)
+			blockchain.hc.engine = blockchain.engine
 			failRes, err = blockchain.InsertHeaderChain(headers, 1)
 			failRes, err = blockchain.InsertHeaderChain(headers, 1)
 		}
 		}
 		// Check that the returned error indicates the nonce failure.
 		// Check that the returned error indicates the nonce failure.
 		if failRes != failAt {
 		if failRes != failAt {
 			t.Errorf("test %d: failure index mismatch: have %d, want %d", i, failRes, failAt)
 			t.Errorf("test %d: failure index mismatch: have %d, want %d", i, failRes, failAt)
 		}
 		}
-		if !IsBlockNonceErr(err) {
-			t.Fatalf("test %d: error mismatch: have %v, want nonce error %T", i, err, err)
-		}
-		nerr := err.(*BlockNonceErr)
-		if nerr.Number.Uint64() != failNum {
-			t.Errorf("test %d: number mismatch: have %v, want %v", i, nerr.Number, failNum)
-		}
-		if nerr.Hash != failHash {
-			t.Errorf("test %d: hash mismatch: have %x, want %x", i, nerr.Hash[:4], failHash[:4])
+		if err != ethash.ErrInvalidPoW {
+			t.Fatalf("test %d: error mismatch: have %v, want %v", i, err, ethash.ErrInvalidPoW)
 		}
 		}
 		// Check that all no blocks after the failing block have been inserted.
 		// Check that all no blocks after the failing block have been inserted.
 		for j := 0; j < i-failAt; j++ {
 		for j := 0; j < i-failAt; j++ {
@@ -569,9 +563,12 @@ func TestFastVsFullChains(t *testing.T) {
 		key, _   = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		key, _   = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		address  = crypto.PubkeyToAddress(key.PublicKey)
 		address  = crypto.PubkeyToAddress(key.PublicKey)
 		funds    = big.NewInt(1000000000)
 		funds    = big.NewInt(1000000000)
-		gspec    = testGenesis(address, funds)
-		genesis  = gspec.MustCommit(gendb)
-		signer   = types.NewEIP155Signer(gspec.Config.ChainId)
+		gspec    = &Genesis{
+			Config: params.TestChainConfig,
+			Alloc:  GenesisAlloc{address: {Balance: funds}},
+		}
+		genesis = gspec.MustCommit(gendb)
+		signer  = types.NewEIP155Signer(gspec.Config.ChainId)
 	)
 	)
 	blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, 1024, func(i int, block *BlockGen) {
 	blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, 1024, func(i int, block *BlockGen) {
 		block.SetCoinbase(common.Address{0x00})
 		block.SetCoinbase(common.Address{0x00})
@@ -594,7 +591,7 @@ func TestFastVsFullChains(t *testing.T) {
 	// Import the chain as an archive node for the comparison baseline
 	// Import the chain as an archive node for the comparison baseline
 	archiveDb, _ := ethdb.NewMemDatabase()
 	archiveDb, _ := ethdb.NewMemDatabase()
 	gspec.MustCommit(archiveDb)
 	gspec.MustCommit(archiveDb)
-	archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 	if n, err := archive.InsertChain(blocks); err != nil {
 	if n, err := archive.InsertChain(blocks); err != nil {
 		t.Fatalf("failed to process block %d: %v", n, err)
 		t.Fatalf("failed to process block %d: %v", n, err)
@@ -603,7 +600,7 @@ func TestFastVsFullChains(t *testing.T) {
 	// Fast import the chain as a non-archive node to test
 	// Fast import the chain as a non-archive node to test
 	fastDb, _ := ethdb.NewMemDatabase()
 	fastDb, _ := ethdb.NewMemDatabase()
 	gspec.MustCommit(fastDb)
 	gspec.MustCommit(fastDb)
-	fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 	headers := make([]*types.Header, len(blocks))
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {
 	for i, block := range blocks {
@@ -680,8 +677,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 	archiveDb, _ := ethdb.NewMemDatabase()
 	archiveDb, _ := ethdb.NewMemDatabase()
 	gspec.MustCommit(archiveDb)
 	gspec.MustCommit(archiveDb)
 
 
-	archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
-
+	archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 	if n, err := archive.InsertChain(blocks); err != nil {
 	if n, err := archive.InsertChain(blocks); err != nil {
 		t.Fatalf("failed to process block %d: %v", n, err)
 		t.Fatalf("failed to process block %d: %v", n, err)
 	}
 	}
@@ -692,7 +688,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 	// Import the chain as a non-archive node and ensure all pointers are updated
 	// Import the chain as a non-archive node and ensure all pointers are updated
 	fastDb, _ := ethdb.NewMemDatabase()
 	fastDb, _ := ethdb.NewMemDatabase()
 	gspec.MustCommit(fastDb)
 	gspec.MustCommit(fastDb)
-	fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 	headers := make([]*types.Header, len(blocks))
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {
 	for i, block := range blocks {
@@ -711,8 +707,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 	// Import the chain as a light node and ensure all pointers are updated
 	// Import the chain as a light node and ensure all pointers are updated
 	lightDb, _ := ethdb.NewMemDatabase()
 	lightDb, _ := ethdb.NewMemDatabase()
 	gspec.MustCommit(lightDb)
 	gspec.MustCommit(lightDb)
-	light, _ := NewBlockChain(lightDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
 
 
+	light, _ := NewBlockChain(lightDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 	if n, err := light.InsertHeaderChain(headers, 1); err != nil {
 	if n, err := light.InsertHeaderChain(headers, 1); err != nil {
 		t.Fatalf("failed to insert header %d: %v", n, err)
 		t.Fatalf("failed to insert header %d: %v", n, err)
 	}
 	}
@@ -780,7 +776,7 @@ func TestChainTxReorgs(t *testing.T) {
 	})
 	})
 	// Import the chain. This runs all block validation rules.
 	// Import the chain. This runs all block validation rules.
 	evmux := &event.TypeMux{}
 	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), evmux, vm.Config{})
 	if i, err := blockchain.InsertChain(chain); err != nil {
 	if i, err := blockchain.InsertChain(chain); err != nil {
 		t.Fatalf("failed to insert original chain[%d]: %v", i, err)
 		t.Fatalf("failed to insert original chain[%d]: %v", i, err)
 	}
 	}
@@ -851,7 +847,7 @@ func TestLogReorgs(t *testing.T) {
 	)
 	)
 
 
 	var evmux event.TypeMux
 	var evmux event.TypeMux
-	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &evmux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), &evmux, vm.Config{})
 
 
 	subs := evmux.Subscribe(RemovedLogsEvent{})
 	subs := evmux.Subscribe(RemovedLogsEvent{})
 	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
 	chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
@@ -883,13 +879,16 @@ func TestReorgSideEvent(t *testing.T) {
 		db, _   = ethdb.NewMemDatabase()
 		db, _   = ethdb.NewMemDatabase()
 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
 		addr1   = crypto.PubkeyToAddress(key1.PublicKey)
 		addr1   = crypto.PubkeyToAddress(key1.PublicKey)
-		gspec   = testGenesis(addr1, big.NewInt(10000000000000))
+		gspec   = &Genesis{
+			Config: params.TestChainConfig,
+			Alloc:  GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}},
+		}
 		genesis = gspec.MustCommit(db)
 		genesis = gspec.MustCommit(db)
 		signer  = types.NewEIP155Signer(gspec.Config.ChainId)
 		signer  = types.NewEIP155Signer(gspec.Config.ChainId)
 	)
 	)
 
 
 	evmux := &event.TypeMux{}
 	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), evmux, vm.Config{})
 
 
 	chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {})
 	chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {})
 	if _, err := blockchain.InsertChain(chain); err != nil {
 	if _, err := blockchain.InsertChain(chain); err != nil {
@@ -959,7 +958,7 @@ done:
 
 
 // Tests if the canonical block can be fetched from the database during chain insertion.
 // Tests if the canonical block can be fetched from the database during chain insertion.
 func TestCanonicalBlockRetrieval(t *testing.T) {
 func TestCanonicalBlockRetrieval(t *testing.T) {
-	bc := newTestBlockChain()
+	bc := newTestBlockChain(false)
 	chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {})
 	chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {})
 
 
 	for i := range chain {
 	for i := range chain {
@@ -1004,7 +1003,7 @@ func TestEIP155Transition(t *testing.T) {
 		mux     event.TypeMux
 		mux     event.TypeMux
 	)
 	)
 
 
-	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), &mux, vm.Config{})
 	blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) {
 	blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) {
 		var (
 		var (
 			tx      *types.Transaction
 			tx      *types.Transaction
@@ -1110,7 +1109,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
 		}
 		}
 		genesis       = gspec.MustCommit(db)
 		genesis       = gspec.MustCommit(db)
 		mux           event.TypeMux
 		mux           event.TypeMux
-		blockchain, _ = NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
+		blockchain, _ = NewBlockChain(db, gspec.Config, ethash.NewFaker(), &mux, vm.Config{})
 	)
 	)
 	blocks, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, block *BlockGen) {
 	blocks, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, block *BlockGen) {
 		var (
 		var (

+ 7 - 6
core/chain_makers.go

@@ -21,13 +21,14 @@ import (
 	"math/big"
 	"math/big"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
+	"github.com/ethereum/go-ethereum/consensus/misc"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 // So we can deterministically seed different blockchains
 // So we can deterministically seed different blockchains
@@ -141,7 +142,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
 	if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
 	if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
 		panic("block time out of range")
 		panic("block time out of range")
 	}
 	}
-	b.header.Difficulty = CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
+	b.header.Difficulty = ethash.CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
 }
 }
 
 
 // GenerateChain creates a chain of n blocks. The first block's
 // GenerateChain creates a chain of n blocks. The first block's
@@ -173,13 +174,13 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Dat
 			}
 			}
 		}
 		}
 		if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(h.Number) == 0 {
 		if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(h.Number) == 0 {
-			ApplyDAOHardFork(statedb)
+			misc.ApplyDAOHardFork(statedb)
 		}
 		}
 		// Execute any user modifications to the block and finalize it
 		// Execute any user modifications to the block and finalize it
 		if gen != nil {
 		if gen != nil {
 			gen(i, b)
 			gen(i, b)
 		}
 		}
-		AccumulateRewards(statedb, h, b.uncles)
+		ethash.AccumulateRewards(statedb, h, b.uncles)
 		root, err := statedb.Commit(config.IsEIP158(h.Number))
 		root, err := statedb.Commit(config.IsEIP158(h.Number))
 		if err != nil {
 		if err != nil {
 			panic(fmt.Sprintf("state write error: %v", err))
 			panic(fmt.Sprintf("state write error: %v", err))
@@ -212,7 +213,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
 		Root:       state.IntermediateRoot(config.IsEIP158(parent.Number())),
 		Root:       state.IntermediateRoot(config.IsEIP158(parent.Number())),
 		ParentHash: parent.Hash(),
 		ParentHash: parent.Hash(),
 		Coinbase:   parent.Coinbase(),
 		Coinbase:   parent.Coinbase(),
-		Difficulty: CalcDifficulty(config, time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
+		Difficulty: ethash.CalcDifficulty(config, time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
 		GasLimit:   CalcGasLimit(parent),
 		GasLimit:   CalcGasLimit(parent),
 		GasUsed:    new(big.Int),
 		GasUsed:    new(big.Int),
 		Number:     new(big.Int).Add(parent.Number(), common.Big1),
 		Number:     new(big.Int).Add(parent.Number(), common.Big1),
@@ -229,7 +230,7 @@ func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
 	db, _ := ethdb.NewMemDatabase()
 	db, _ := ethdb.NewMemDatabase()
 	genesis := gspec.MustCommit(db)
 	genesis := gspec.MustCommit(db)
 
 
-	blockchain, _ := NewBlockChain(db, params.AllProtocolChanges, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+	blockchain, _ := NewBlockChain(db, params.AllProtocolChanges, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 	// Create and inject the requested chain
 	// Create and inject the requested chain
 	if n == 0 {
 	if n == 0 {
 		return db, blockchain, nil
 		return db, blockchain, nil

+ 2 - 2
core/chain_makers_test.go

@@ -20,13 +20,13 @@ import (
 	"fmt"
 	"fmt"
 	"math/big"
 	"math/big"
 
 
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 func ExampleGenerateChain() {
 func ExampleGenerateChain() {
@@ -81,7 +81,7 @@ func ExampleGenerateChain() {
 
 
 	// Import the chain. This runs all block validation rules.
 	// Import the chain. This runs all block validation rules.
 	evmux := &event.TypeMux{}
 	evmux := &event.TypeMux{}
-	blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
+	blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), evmux, vm.Config{})
 	if i, err := blockchain.InsertChain(chain); err != nil {
 	if i, err := blockchain.InsertChain(chain); err != nil {
 		fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
 		fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
 		return
 		return

+ 0 - 87
core/chain_pow.go

@@ -1,87 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package core
-
-import (
-	"runtime"
-
-	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/pow"
-)
-
-// nonceCheckResult contains the result of a nonce verification.
-type nonceCheckResult struct {
-	index int  // Index of the item verified from an input array
-	valid bool // Result of the nonce verification
-}
-
-// verifyNoncesFromHeaders starts a concurrent header nonce verification,
-// returning a quit channel to abort the operations and a results channel
-// to retrieve the async verifications.
-func verifyNoncesFromHeaders(checker pow.PoW, headers []*types.Header) (chan<- struct{}, <-chan nonceCheckResult) {
-	items := make([]pow.Block, len(headers))
-	for i, header := range headers {
-		items[i] = types.NewBlockWithHeader(header)
-	}
-	return verifyNonces(checker, items)
-}
-
-// verifyNoncesFromBlocks starts a concurrent block nonce verification,
-// returning a quit channel to abort the operations and a results channel
-// to retrieve the async verifications.
-func verifyNoncesFromBlocks(checker pow.PoW, blocks []*types.Block) (chan<- struct{}, <-chan nonceCheckResult) {
-	items := make([]pow.Block, len(blocks))
-	for i, block := range blocks {
-		items[i] = block
-	}
-	return verifyNonces(checker, items)
-}
-
-// verifyNonces starts a concurrent nonce verification, returning a quit channel
-// to abort the operations and a results channel to retrieve the async checks.
-func verifyNonces(checker pow.PoW, items []pow.Block) (chan<- struct{}, <-chan nonceCheckResult) {
-	// Spawn as many workers as allowed threads
-	workers := runtime.GOMAXPROCS(0)
-	if len(items) < workers {
-		workers = len(items)
-	}
-	// Create a task channel and spawn the verifiers
-	tasks := make(chan int, workers)
-	results := make(chan nonceCheckResult, len(items)) // Buffered to make sure all workers stop
-	for i := 0; i < workers; i++ {
-		go func() {
-			for index := range tasks {
-				results <- nonceCheckResult{index: index, valid: checker.Verify(items[index]) == nil}
-			}
-		}()
-	}
-	// Feed item indices to the workers until done or aborted
-	abort := make(chan struct{})
-	go func() {
-		defer close(tasks)
-
-		for i := range items {
-			select {
-			case tasks <- i:
-				continue
-			case <-abort:
-				return
-			}
-		}
-	}()
-	return abort, results
-}

+ 0 - 238
core/chain_pow_test.go

@@ -1,238 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package core
-
-import (
-	"errors"
-	"math/big"
-	"runtime"
-	"testing"
-	"time"
-
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/ethdb"
-	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
-)
-
-// failPow is a non-validating proof of work implementation, that returns true
-// from Verify for all but one block.
-type failPow struct {
-	failing uint64
-}
-
-func (pow failPow) Search(pow.Block, <-chan struct{}) (uint64, []byte) {
-	return 0, nil
-}
-func (pow failPow) Verify(block pow.Block) error {
-	if block.NumberU64() == pow.failing {
-		return errors.New("failed")
-	}
-	return nil
-}
-func (pow failPow) Hashrate() float64 { return 0 }
-
-// delayedPow is a non-validating proof of work implementation, that returns true
-// from Verify for all blocks, but delays them the configured amount of time.
-type delayedPow struct {
-	delay time.Duration
-}
-
-func (pow delayedPow) Search(pow.Block, <-chan struct{}) (uint64, []byte) {
-	return 0, nil
-}
-func (pow delayedPow) Verify(block pow.Block) error { time.Sleep(pow.delay); return nil }
-func (pow delayedPow) Hashrate() float64            { return 0 }
-
-// Tests that simple POW verification works, for both good and bad blocks.
-func TestPowVerification(t *testing.T) {
-	// Create a simple chain to verify
-	var (
-		testdb, _ = ethdb.NewMemDatabase()
-		genesis   = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
-		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
-	)
-	headers := make([]*types.Header, len(blocks))
-	for i, block := range blocks {
-		headers[i] = block.Header()
-	}
-	// Run the POW checker for blocks one-by-one, checking for both valid and invalid nonces
-	for i := 0; i < len(blocks); i++ {
-		for j, full := range []bool{true, false} {
-			for k, valid := range []bool{true, false} {
-				var results <-chan nonceCheckResult
-
-				switch {
-				case full && valid:
-					_, results = verifyNoncesFromBlocks(pow.FakePow{}, []*types.Block{blocks[i]})
-				case full && !valid:
-					_, results = verifyNoncesFromBlocks(failPow{blocks[i].NumberU64()}, []*types.Block{blocks[i]})
-				case !full && valid:
-					_, results = verifyNoncesFromHeaders(pow.FakePow{}, []*types.Header{headers[i]})
-				case !full && !valid:
-					_, results = verifyNoncesFromHeaders(failPow{headers[i].Number.Uint64()}, []*types.Header{headers[i]})
-				}
-				// Wait for the verification result
-				select {
-				case result := <-results:
-					if result.index != 0 {
-						t.Errorf("test %d.%d.%d: invalid index: have %d, want 0", i, j, k, result.index)
-					}
-					if result.valid != valid {
-						t.Errorf("test %d.%d.%d: validity mismatch: have %v, want %v", i, j, k, result.valid, valid)
-					}
-				case <-time.After(time.Second):
-					t.Fatalf("test %d.%d.%d: verification timeout", i, j, k)
-				}
-				// Make sure no more data is returned
-				select {
-				case result := <-results:
-					t.Fatalf("test %d.%d.%d: unexpected result returned: %v", i, j, k, result)
-				case <-time.After(25 * time.Millisecond):
-				}
-			}
-		}
-	}
-}
-
-// Tests that concurrent POW verification works, for both good and bad blocks.
-func TestPowConcurrentVerification2(t *testing.T)  { testPowConcurrentVerification(t, 2) }
-func TestPowConcurrentVerification8(t *testing.T)  { testPowConcurrentVerification(t, 8) }
-func TestPowConcurrentVerification32(t *testing.T) { testPowConcurrentVerification(t, 32) }
-
-func testPowConcurrentVerification(t *testing.T, threads int) {
-	// Create a simple chain to verify
-	var (
-		testdb, _ = ethdb.NewMemDatabase()
-		genesis   = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
-		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
-	)
-	headers := make([]*types.Header, len(blocks))
-	for i, block := range blocks {
-		headers[i] = block.Header()
-	}
-	// Set the number of threads to verify on
-	old := runtime.GOMAXPROCS(threads)
-	defer runtime.GOMAXPROCS(old)
-
-	// Run the POW checker for the entire block chain at once both for a valid and
-	// also an invalid chain (enough if one is invalid, last but one (arbitrary)).
-	for i, full := range []bool{true, false} {
-		for j, valid := range []bool{true, false} {
-			var results <-chan nonceCheckResult
-
-			switch {
-			case full && valid:
-				_, results = verifyNoncesFromBlocks(pow.FakePow{}, blocks)
-			case full && !valid:
-				_, results = verifyNoncesFromBlocks(failPow{uint64(len(blocks) - 1)}, blocks)
-			case !full && valid:
-				_, results = verifyNoncesFromHeaders(pow.FakePow{}, headers)
-			case !full && !valid:
-				_, results = verifyNoncesFromHeaders(failPow{uint64(len(headers) - 1)}, headers)
-			}
-			// Wait for all the verification results
-			checks := make(map[int]bool)
-			for k := 0; k < len(blocks); k++ {
-				select {
-				case result := <-results:
-					if _, ok := checks[result.index]; ok {
-						t.Fatalf("test %d.%d.%d: duplicate results for %d", i, j, k, result.index)
-					}
-					if result.index < 0 || result.index >= len(blocks) {
-						t.Fatalf("test %d.%d.%d: result %d out of bounds [%d, %d]", i, j, k, result.index, 0, len(blocks)-1)
-					}
-					checks[result.index] = result.valid
-
-				case <-time.After(time.Second):
-					t.Fatalf("test %d.%d.%d: verification timeout", i, j, k)
-				}
-			}
-			// Check nonce check validity
-			for k := 0; k < len(blocks); k++ {
-				want := valid || (k != len(blocks)-2) // We chose the last but one nonce in the chain to fail
-				if checks[k] != want {
-					t.Errorf("test %d.%d.%d: validity mismatch: have %v, want %v", i, j, k, checks[k], want)
-				}
-			}
-			// Make sure no more data is returned
-			select {
-			case result := <-results:
-				t.Fatalf("test %d.%d: unexpected result returned: %v", i, j, result)
-			case <-time.After(25 * time.Millisecond):
-			}
-		}
-	}
-}
-
-// Tests that aborting a POW validation indeed prevents further checks from being
-// run, as well as checks that no left-over goroutines are leaked.
-func TestPowConcurrentAbortion2(t *testing.T)  { testPowConcurrentAbortion(t, 2) }
-func TestPowConcurrentAbortion8(t *testing.T)  { testPowConcurrentAbortion(t, 8) }
-func TestPowConcurrentAbortion32(t *testing.T) { testPowConcurrentAbortion(t, 32) }
-
-func testPowConcurrentAbortion(t *testing.T, threads int) {
-	// Create a simple chain to verify
-	var (
-		testdb, _ = ethdb.NewMemDatabase()
-		genesis   = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
-		blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 1024, nil)
-	)
-	headers := make([]*types.Header, len(blocks))
-	for i, block := range blocks {
-		headers[i] = block.Header()
-	}
-	// Set the number of threads to verify on
-	old := runtime.GOMAXPROCS(threads)
-	defer runtime.GOMAXPROCS(old)
-
-	// Run the POW checker for the entire block chain at once
-	for i, full := range []bool{true, false} {
-		var abort chan<- struct{}
-		var results <-chan nonceCheckResult
-
-		// Start the verifications and immediately abort
-		if full {
-			abort, results = verifyNoncesFromBlocks(delayedPow{time.Millisecond}, blocks)
-		} else {
-			abort, results = verifyNoncesFromHeaders(delayedPow{time.Millisecond}, headers)
-		}
-		close(abort)
-
-		// Deplete the results channel
-		verified := make(map[int]struct{})
-		for depleted := false; !depleted; {
-			select {
-			case result := <-results:
-				verified[result.index] = struct{}{}
-			case <-time.After(50 * time.Millisecond):
-				depleted = true
-			}
-		}
-		// Check that abortion was honored by not processing too many POWs
-		if len(verified) > 2*threads {
-			t.Errorf("test %d: verification count too large: have %d, want below %d", i, len(verified), 2*threads)
-		}
-		// Check that there are no gaps in the results
-		for j := 0; j < len(verified); j++ {
-			if _, ok := verified[j]; !ok {
-				t.Errorf("test %d.%d: gap found in verification results", i, j)
-			}
-		}
-	}
-}

+ 7 - 7
core/dao_test.go

@@ -20,11 +20,11 @@ import (
 	"math/big"
 	"math/big"
 	"testing"
 	"testing"
 
 
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 // Tests that DAO-fork enabled clients can properly filter out fork-commencing
 // Tests that DAO-fork enabled clients can properly filter out fork-commencing
@@ -42,12 +42,12 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	proDb, _ := ethdb.NewMemDatabase()
 	proDb, _ := ethdb.NewMemDatabase()
 	gspec.MustCommit(proDb)
 	gspec.MustCommit(proDb)
 	proConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
 	proConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
-	proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
+	proBc, _ := NewBlockChain(proDb, proConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 	conDb, _ := ethdb.NewMemDatabase()
 	conDb, _ := ethdb.NewMemDatabase()
 	gspec.MustCommit(conDb)
 	gspec.MustCommit(conDb)
 	conConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
 	conConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
-	conBc, _ := NewBlockChain(conDb, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
+	conBc, _ := NewBlockChain(conDb, conConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 	if _, err := proBc.InsertChain(prefix); err != nil {
 	if _, err := proBc.InsertChain(prefix); err != nil {
 		t.Fatalf("pro-fork: failed to import chain prefix: %v", err)
 		t.Fatalf("pro-fork: failed to import chain prefix: %v", err)
@@ -60,7 +60,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 		// Create a pro-fork block, and try to feed into the no-fork chain
 		// Create a pro-fork block, and try to feed into the no-fork chain
 		db, _ = ethdb.NewMemDatabase()
 		db, _ = ethdb.NewMemDatabase()
 		gspec.MustCommit(db)
 		gspec.MustCommit(db)
-		bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
+		bc, _ := NewBlockChain(db, conConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 		blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
 		blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
 		for j := 0; j < len(blocks)/2; j++ {
 		for j := 0; j < len(blocks)/2; j++ {
@@ -81,7 +81,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 		// Create a no-fork block, and try to feed into the pro-fork chain
 		// Create a no-fork block, and try to feed into the pro-fork chain
 		db, _ = ethdb.NewMemDatabase()
 		db, _ = ethdb.NewMemDatabase()
 		gspec.MustCommit(db)
 		gspec.MustCommit(db)
-		bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
+		bc, _ = NewBlockChain(db, proConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 		blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
 		blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
 		for j := 0; j < len(blocks)/2; j++ {
 		for j := 0; j < len(blocks)/2; j++ {
@@ -103,7 +103,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
 	// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
 	db, _ = ethdb.NewMemDatabase()
 	db, _ = ethdb.NewMemDatabase()
 	gspec.MustCommit(db)
 	gspec.MustCommit(db)
-	bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
+	bc, _ := NewBlockChain(db, conConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 	blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
 	blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
 	for j := 0; j < len(blocks)/2; j++ {
 	for j := 0; j < len(blocks)/2; j++ {
@@ -119,7 +119,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
 	// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
 	db, _ = ethdb.NewMemDatabase()
 	db, _ = ethdb.NewMemDatabase()
 	gspec.MustCommit(db)
 	gspec.MustCommit(db)
-	bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
+	bc, _ = NewBlockChain(db, proConf, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
 
 
 	blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
 	blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
 	for j := 0; j < len(blocks)/2; j++ {
 	for j := 0; j < len(blocks)/2; j++ {

+ 5 - 55
core/database_util_test.go

@@ -18,14 +18,12 @@ package core
 
 
 import (
 import (
 	"bytes"
 	"bytes"
-	"encoding/json"
 	"io/ioutil"
 	"io/ioutil"
 	"math/big"
 	"math/big"
 	"os"
 	"os"
 	"testing"
 	"testing"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/crypto/sha3"
 	"github.com/ethereum/go-ethereum/crypto/sha3"
@@ -34,58 +32,6 @@ import (
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 )
 )
 
 
-type diffTest struct {
-	ParentTimestamp    uint64
-	ParentDifficulty   *big.Int
-	CurrentTimestamp   uint64
-	CurrentBlocknumber *big.Int
-	CurrentDifficulty  *big.Int
-}
-
-func (d *diffTest) UnmarshalJSON(b []byte) (err error) {
-	var ext struct {
-		ParentTimestamp    string
-		ParentDifficulty   string
-		CurrentTimestamp   string
-		CurrentBlocknumber string
-		CurrentDifficulty  string
-	}
-	if err := json.Unmarshal(b, &ext); err != nil {
-		return err
-	}
-
-	d.ParentTimestamp = math.MustParseUint64(ext.ParentTimestamp)
-	d.ParentDifficulty = math.MustParseBig256(ext.ParentDifficulty)
-	d.CurrentTimestamp = math.MustParseUint64(ext.CurrentTimestamp)
-	d.CurrentBlocknumber = math.MustParseBig256(ext.CurrentBlocknumber)
-	d.CurrentDifficulty = math.MustParseBig256(ext.CurrentDifficulty)
-
-	return nil
-}
-
-func TestCalcDifficulty(t *testing.T) {
-	file, err := os.Open("../tests/files/BasicTests/difficulty.json")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer file.Close()
-
-	tests := make(map[string]diffTest)
-	err = json.NewDecoder(file).Decode(&tests)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	config := &params.ChainConfig{HomesteadBlock: big.NewInt(1150000)}
-	for name, test := range tests {
-		number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
-		diff := CalcDifficulty(config, test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty)
-		if diff.Cmp(test.CurrentDifficulty) != 0 {
-			t.Error(name, "failed. Expected", test.CurrentDifficulty, "and calculated", diff)
-		}
-	}
-}
-
 // Tests block header storage and retrieval operations.
 // Tests block header storage and retrieval operations.
 func TestHeaderStorage(t *testing.T) {
 func TestHeaderStorage(t *testing.T) {
 	db, _ := ethdb.NewMemDatabase()
 	db, _ := ethdb.NewMemDatabase()
@@ -562,7 +508,11 @@ func TestMipmapChain(t *testing.T) {
 	)
 	)
 	defer db.Close()
 	defer db.Close()
 
 
-	genesis := testGenesis(addr, big.NewInt(1000000)).MustCommit(db)
+	gspec := &Genesis{
+		Config: params.TestChainConfig,
+		Alloc:  GenesisAlloc{addr: {Balance: big.NewInt(1000000)}},
+	}
+	genesis := gspec.MustCommit(db)
 	chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
 	chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
 		var receipts types.Receipts
 		var receipts types.Receipts
 		switch i {
 		switch i {

+ 2 - 2
core/genesis_test.go

@@ -23,11 +23,11 @@ import (
 
 
 	"github.com/davecgh/go-spew/spew"
 	"github.com/davecgh/go-spew/spew"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 func TestDefaultGenesisBlock(t *testing.T) {
 func TestDefaultGenesisBlock(t *testing.T) {
@@ -119,7 +119,7 @@ func TestSetupGenesis(t *testing.T) {
 				// Commit the 'old' genesis block with Homestead transition at #2.
 				// Commit the 'old' genesis block with Homestead transition at #2.
 				// Advance to block #4, past the homestead transition block of customg.
 				// Advance to block #4, past the homestead transition block of customg.
 				genesis := oldcustomg.MustCommit(db)
 				genesis := oldcustomg.MustCommit(db)
-				bc, _ := NewBlockChain(db, oldcustomg.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
+				bc, _ := NewBlockChain(db, oldcustomg.Config, ethash.NewFullFaker(), new(event.TypeMux), vm.Config{})
 				bc.SetValidator(bproc{})
 				bc.SetValidator(bproc{})
 				bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
 				bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
 				bc.CurrentBlock()
 				bc.CurrentBlock()

+ 37 - 112
core/headerchain.go

@@ -18,21 +18,19 @@ package core
 
 
 import (
 import (
 	crand "crypto/rand"
 	crand "crypto/rand"
+	"errors"
 	"fmt"
 	"fmt"
 	"math"
 	"math"
 	"math/big"
 	"math/big"
 	mrand "math/rand"
 	mrand "math/rand"
-	"runtime"
-	"sync"
-	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/hashicorp/golang-lru"
 	"github.com/hashicorp/golang-lru"
 )
 )
 
 
@@ -62,18 +60,15 @@ type HeaderChain struct {
 
 
 	procInterrupt func() bool
 	procInterrupt func() bool
 
 
-	rand         *mrand.Rand
-	getValidator getHeaderValidatorFn
+	rand   *mrand.Rand
+	engine consensus.Engine
 }
 }
 
 
-// getHeaderValidatorFn returns a HeaderValidator interface
-type getHeaderValidatorFn func() HeaderValidator
-
 // NewHeaderChain creates a new HeaderChain structure.
 // NewHeaderChain creates a new HeaderChain structure.
 //  getValidator should return the parent's validator
 //  getValidator should return the parent's validator
 //  procInterrupt points to the parent's interrupt semaphore
 //  procInterrupt points to the parent's interrupt semaphore
 //  wg points to the parent's shutdown wait group
 //  wg points to the parent's shutdown wait group
-func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) {
+func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) {
 	headerCache, _ := lru.New(headerCacheLimit)
 	headerCache, _ := lru.New(headerCacheLimit)
 	tdCache, _ := lru.New(tdCacheLimit)
 	tdCache, _ := lru.New(tdCacheLimit)
 	numberCache, _ := lru.New(numberCacheLimit)
 	numberCache, _ := lru.New(numberCacheLimit)
@@ -92,7 +87,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValid
 		numberCache:   numberCache,
 		numberCache:   numberCache,
 		procInterrupt: procInterrupt,
 		procInterrupt: procInterrupt,
 		rand:          mrand.New(mrand.NewSource(seed.Int64())),
 		rand:          mrand.New(mrand.NewSource(seed.Int64())),
-		getValidator:  getValidator,
+		engine:        engine,
 	}
 	}
 
 
 	hc.genesisHeader = hc.GetHeaderByNumber(0)
 	hc.genesisHeader = hc.GetHeaderByNumber(0)
@@ -228,78 +223,34 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header, checkFreq int)
 		}
 		}
 	}
 	}
 
 
-	// Generate the list of headers that should be POW verified
-	verify := make([]bool, len(chain))
-	for i := 0; i < len(verify)/checkFreq; i++ {
+	// Generate the list of seal verification requests, and start the parallel verifier
+	seals := make([]bool, len(chain))
+	for i := 0; i < len(seals)/checkFreq; i++ {
 		index := i*checkFreq + hc.rand.Intn(checkFreq)
 		index := i*checkFreq + hc.rand.Intn(checkFreq)
-		if index >= len(verify) {
-			index = len(verify) - 1
+		if index >= len(seals) {
+			index = len(seals) - 1
 		}
 		}
-		verify[index] = true
-	}
-	verify[len(verify)-1] = true // Last should always be verified to avoid junk
-
-	// Create the header verification task queue and worker functions
-	tasks := make(chan int, len(chain))
-	for i := 0; i < len(chain); i++ {
-		tasks <- i
+		seals[index] = true
 	}
 	}
-	close(tasks)
+	seals[len(seals)-1] = true // Last should always be verified to avoid junk
 
 
-	errs, failed := make([]error, len(tasks)), int32(0)
-	process := func(worker int) {
-		for index := range tasks {
-			header, hash := chain[index], chain[index].Hash()
+	abort, results := hc.engine.VerifyHeaders(hc, chain, seals)
+	defer close(abort)
 
 
-			// Short circuit insertion if shutting down or processing failed
-			if hc.procInterrupt() {
-				return
-			}
-			if atomic.LoadInt32(&failed) > 0 {
-				return
-			}
-			// Short circuit if the header is bad or already known
-			if BadHashes[hash] {
-				errs[index] = BadHashError(hash)
-				atomic.AddInt32(&failed, 1)
-				return
-			}
-			if hc.HasHeader(hash) {
-				continue
-			}
-			// Verify that the header honors the chain parameters
-			checkPow := verify[index]
-
-			var err error
-			if index == 0 {
-				err = hc.getValidator().ValidateHeader(header, hc.GetHeader(header.ParentHash, header.Number.Uint64()-1), checkPow)
-			} else {
-				err = hc.getValidator().ValidateHeader(header, chain[index-1], checkPow)
-			}
-			if err != nil {
-				errs[index] = err
-				atomic.AddInt32(&failed, 1)
-				return
-			}
+	// Iterate over the headers and ensure they all check out
+	for i, header := range chain {
+		// If the chain is terminating, stop processing blocks
+		if hc.procInterrupt() {
+			log.Debug("Premature abort during headers verification")
+			return 0, errors.New("aborted")
 		}
 		}
-	}
-	// Start as many worker threads as goroutines allowed
-	pending := new(sync.WaitGroup)
-	for i := 0; i < runtime.GOMAXPROCS(0); i++ {
-		pending.Add(1)
-		go func(id int) {
-			defer pending.Done()
-			process(id)
-		}(i)
-	}
-	pending.Wait()
-
-	// If anything failed, report
-	if failed > 0 {
-		for i, err := range errs {
-			if err != nil {
-				return i, err
-			}
+		// If the header is a banned one, straight out abort
+		if BadHashes[header.Hash()] {
+			return i, BadHashError(header.Hash())
+		}
+		// Otherwise wait for headers checks and ensure they pass
+		if err := <-results; err != nil {
+			return i, err
 		}
 		}
 	}
 	}
 
 
@@ -313,13 +264,11 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCa
 	for i, header := range chain {
 	for i, header := range chain {
 		// Short circuit insertion if shutting down
 		// Short circuit insertion if shutting down
 		if hc.procInterrupt() {
 		if hc.procInterrupt() {
-			log.Debug("Premature abort during headers processing")
-			break
+			log.Debug("Premature abort during headers import")
+			return i, errors.New("aborted")
 		}
 		}
-		hash := header.Hash()
-
 		// If the header's already known, skip it, otherwise store
 		// If the header's already known, skip it, otherwise store
-		if hc.HasHeader(hash) {
+		if hc.GetHeader(header.Hash(), header.Number.Uint64()) != nil {
 			stats.ignored++
 			stats.ignored++
 			continue
 			continue
 		}
 		}
@@ -490,35 +439,11 @@ func (hc *HeaderChain) SetGenesis(head *types.Header) {
 	hc.genesisHeader = head
 	hc.genesisHeader = head
 }
 }
 
 
-// headerValidator is responsible for validating block headers
-//
-// headerValidator implements HeaderValidator.
-type headerValidator struct {
-	config *params.ChainConfig
-	hc     *HeaderChain // Canonical header chain
-	Pow    pow.PoW      // Proof of work used for validating
-}
-
-// NewBlockValidator returns a new block validator which is safe for re-use
-func NewHeaderValidator(config *params.ChainConfig, chain *HeaderChain, pow pow.PoW) HeaderValidator {
-	return &headerValidator{
-		config: config,
-		Pow:    pow,
-		hc:     chain,
-	}
-}
+// Config retrieves the header chain's chain configuration.
+func (hc *HeaderChain) Config() *params.ChainConfig { return hc.config }
 
 
-// ValidateHeader validates the given header and, depending on the pow arg,
-// checks the proof of work of the given header. Returns an error if the
-// validation failed.
-func (v *headerValidator) ValidateHeader(header, parent *types.Header, checkPow bool) error {
-	// Short circuit if the parent is missing.
-	if parent == nil {
-		return ParentError(header.ParentHash)
-	}
-	// Short circuit if the header's already known or its parent missing
-	if v.hc.HasHeader(header.Hash()) {
-		return nil
-	}
-	return ValidateHeader(v.config, v.Pow, header, parent, checkPow, false)
+// GetBlock implements consensus.ChainReader, and returns nil for every input as
+// a header chain does not have blocks available for retrieval.
+func (hc *HeaderChain) GetBlock(hash common.Hash, number uint64) *types.Block {
+	return nil
 }
 }

+ 11 - 33
core/state_processor.go

@@ -19,6 +19,8 @@ package core
 import (
 import (
 	"math/big"
 	"math/big"
 
 
+	"github.com/ethereum/go-ethereum/consensus"
+	"github.com/ethereum/go-ethereum/consensus/misc"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
@@ -26,25 +28,22 @@ import (
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
 )
 )
 
 
-var (
-	big8  = big.NewInt(8)
-	big32 = big.NewInt(32)
-)
-
 // StateProcessor is a basic Processor, which takes care of transitioning
 // StateProcessor is a basic Processor, which takes care of transitioning
 // state from one point to another.
 // state from one point to another.
 //
 //
 // StateProcessor implements Processor.
 // StateProcessor implements Processor.
 type StateProcessor struct {
 type StateProcessor struct {
-	config *params.ChainConfig
-	bc     *BlockChain
+	config *params.ChainConfig // Chain configuration options
+	bc     *BlockChain         // Canonical block chain
+	engine consensus.Engine    // Consensus engine used for block rewards
 }
 }
 
 
 // NewStateProcessor initialises a new StateProcessor.
 // NewStateProcessor initialises a new StateProcessor.
-func NewStateProcessor(config *params.ChainConfig, bc *BlockChain) *StateProcessor {
+func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor {
 	return &StateProcessor{
 	return &StateProcessor{
 		config: config,
 		config: config,
 		bc:     bc,
 		bc:     bc,
+		engine: engine,
 	}
 	}
 }
 }
 
 
@@ -59,18 +58,16 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
 	var (
 	var (
 		receipts     types.Receipts
 		receipts     types.Receipts
 		totalUsedGas = big.NewInt(0)
 		totalUsedGas = big.NewInt(0)
-		err          error
 		header       = block.Header()
 		header       = block.Header()
 		allLogs      []*types.Log
 		allLogs      []*types.Log
 		gp           = new(GasPool).AddGas(block.GasLimit())
 		gp           = new(GasPool).AddGas(block.GasLimit())
 	)
 	)
 	// Mutate the the block and state according to any hard-fork specs
 	// Mutate the the block and state according to any hard-fork specs
 	if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
 	if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
-		ApplyDAOHardFork(statedb)
+		misc.ApplyDAOHardFork(statedb)
 	}
 	}
 	// Iterate over and process the individual transactions
 	// Iterate over and process the individual transactions
 	for i, tx := range block.Transactions() {
 	for i, tx := range block.Transactions() {
-		//fmt.Println("tx:", i)
 		statedb.StartRecord(tx.Hash(), block.Hash(), i)
 		statedb.StartRecord(tx.Hash(), block.Hash(), i)
 		receipt, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
 		receipt, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
 		if err != nil {
 		if err != nil {
@@ -79,9 +76,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
 		receipts = append(receipts, receipt)
 		receipts = append(receipts, receipt)
 		allLogs = append(allLogs, receipt.Logs...)
 		allLogs = append(allLogs, receipt.Logs...)
 	}
 	}
-	AccumulateRewards(statedb, header, block.Uncles())
+	// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
+	p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts)
 
 
-	return receipts, allLogs, totalUsedGas, err
+	return receipts, allLogs, totalUsedGas, nil
 }
 }
 
 
 // ApplyTransaction attempts to apply a transaction to the given state database
 // ApplyTransaction attempts to apply a transaction to the given state database
@@ -122,23 +120,3 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, s
 
 
 	return receipt, gas, err
 	return receipt, gas, err
 }
 }
-
-// AccumulateRewards credits the coinbase of the given block with the
-// mining reward. The total reward consists of the static block reward
-// and rewards for included uncles. The coinbase of each uncle block is
-// also rewarded.
-func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*types.Header) {
-	reward := new(big.Int).Set(BlockReward)
-	r := new(big.Int)
-	for _, uncle := range uncles {
-		r.Add(uncle.Number, big8)
-		r.Sub(r, header.Number)
-		r.Mul(r, BlockReward)
-		r.Div(r, big8)
-		statedb.AddBalance(uncle.Coinbase, r)
-
-		r.Div(BlockReward, big32)
-		reward.Add(reward, r)
-	}
-	statedb.AddBalance(header.Coinbase, reward)
-}

+ 8 - 22
core/types.go

@@ -24,31 +24,17 @@ import (
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 )
 )
 
 
-// Validator is an interface which defines the standard for block validation.
+// Validator is an interface which defines the standard for block validation. It
+// is only responsible for validating block contents, as the header validation is
+// done by the specific consensus engines.
 //
 //
-// The validator is responsible for validating incoming block or, if desired,
-// validates headers for fast validation.
-//
-// ValidateBlock validates the given block and should return an error if it
-// failed to do so and should be used for "full" validation.
-//
-// ValidateHeader validates the given header and parent and returns an error
-// if it failed to do so.
-//
-// ValidateState validates the given statedb and optionally the receipts and
-// gas used. The implementer should decide what to do with the given input.
 type Validator interface {
 type Validator interface {
-	HeaderValidator
-	ValidateBlock(block *types.Block) error
-	ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error
-}
+	// ValidateBody validates the given block's content.
+	ValidateBody(block *types.Block) error
 
 
-// HeaderValidator is an interface for validating headers only
-//
-// ValidateHeader validates the given header and parent and returns an error
-// if it failed to do so.
-type HeaderValidator interface {
-	ValidateHeader(header, parent *types.Header, checkPow bool) error
+	// ValidateState validates the given statedb and optionally the receipts and
+	// gas used.
+	ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error
 }
 }
 
 
 // Processor is an interface for processing blocks using a given initial state.
 // Processor is an interface for processing blocks using a given initial state.

+ 5 - 6
core/types/block.go

@@ -348,12 +348,11 @@ func CalcUncleHash(uncles []*Header) common.Hash {
 	return rlpHash(uncles)
 	return rlpHash(uncles)
 }
 }
 
 
-// WithMiningResult returns a new block with the data from b
-// where nonce and mix digest are set to the provided values.
-func (b *Block) WithMiningResult(nonce BlockNonce, mixDigest common.Hash) *Block {
-	cpy := *b.header
-	cpy.Nonce = nonce
-	cpy.MixDigest = mixDigest
+// WithSeal returns a new block with the data from b but the header replaced with
+// the sealed one.
+func (b *Block) WithSeal(header *Header) *Block {
+	cpy := *header
+
 	return &Block{
 	return &Block{
 		header:       &cpy,
 		header:       &cpy,
 		transactions: b.transactions,
 		transactions: b.transactions,

+ 52 - 41
eth/api.go

@@ -26,7 +26,6 @@ import (
 	"io/ioutil"
 	"io/ioutil"
 	"math/big"
 	"math/big"
 	"os"
 	"os"
-	"runtime"
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
@@ -37,6 +36,7 @@ import (
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
 	"github.com/ethereum/go-ethereum/internal/ethapi"
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/miner"
 	"github.com/ethereum/go-ethereum/miner"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
@@ -56,18 +56,18 @@ func NewPublicEthereumAPI(e *Ethereum) *PublicEthereumAPI {
 }
 }
 
 
 // Etherbase is the address that mining rewards will be send to
 // Etherbase is the address that mining rewards will be send to
-func (s *PublicEthereumAPI) Etherbase() (common.Address, error) {
-	return s.e.Etherbase()
+func (api *PublicEthereumAPI) Etherbase() (common.Address, error) {
+	return api.e.Etherbase()
 }
 }
 
 
 // Coinbase is the address that mining rewards will be send to (alias for Etherbase)
 // Coinbase is the address that mining rewards will be send to (alias for Etherbase)
-func (s *PublicEthereumAPI) Coinbase() (common.Address, error) {
-	return s.Etherbase()
+func (api *PublicEthereumAPI) Coinbase() (common.Address, error) {
+	return api.Etherbase()
 }
 }
 
 
 // Hashrate returns the POW hashrate
 // Hashrate returns the POW hashrate
-func (s *PublicEthereumAPI) Hashrate() hexutil.Uint64 {
-	return hexutil.Uint64(s.e.Miner().HashRate())
+func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 {
+	return hexutil.Uint64(api.e.Miner().HashRate())
 }
 }
 
 
 // PublicMinerAPI provides an API to control the miner.
 // PublicMinerAPI provides an API to control the miner.
@@ -79,34 +79,34 @@ type PublicMinerAPI struct {
 
 
 // NewPublicMinerAPI create a new PublicMinerAPI instance.
 // NewPublicMinerAPI create a new PublicMinerAPI instance.
 func NewPublicMinerAPI(e *Ethereum) *PublicMinerAPI {
 func NewPublicMinerAPI(e *Ethereum) *PublicMinerAPI {
-	agent := miner.NewRemoteAgent(e.Pow())
+	agent := miner.NewRemoteAgent(e.BlockChain(), e.Engine())
 	e.Miner().Register(agent)
 	e.Miner().Register(agent)
 
 
 	return &PublicMinerAPI{e, agent}
 	return &PublicMinerAPI{e, agent}
 }
 }
 
 
 // Mining returns an indication if this node is currently mining.
 // Mining returns an indication if this node is currently mining.
-func (s *PublicMinerAPI) Mining() bool {
-	return s.e.IsMining()
+func (api *PublicMinerAPI) Mining() bool {
+	return api.e.IsMining()
 }
 }
 
 
 // SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was
 // SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was
 // accepted. Note, this is not an indication if the provided work was valid!
 // accepted. Note, this is not an indication if the provided work was valid!
-func (s *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest common.Hash) bool {
-	return s.agent.SubmitWork(nonce, digest, solution)
+func (api *PublicMinerAPI) SubmitWork(nonce types.BlockNonce, solution, digest common.Hash) bool {
+	return api.agent.SubmitWork(nonce, digest, solution)
 }
 }
 
 
 // GetWork returns a work package for external miner. The work package consists of 3 strings
 // GetWork returns a work package for external miner. The work package consists of 3 strings
 // result[0], 32 bytes hex encoded current block header pow-hash
 // result[0], 32 bytes hex encoded current block header pow-hash
 // result[1], 32 bytes hex encoded seed hash used for DAG
 // result[1], 32 bytes hex encoded seed hash used for DAG
 // result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
 // result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
-func (s *PublicMinerAPI) GetWork() ([3]string, error) {
-	if !s.e.IsMining() {
-		if err := s.e.StartMining(0); err != nil {
+func (api *PublicMinerAPI) GetWork() ([3]string, error) {
+	if !api.e.IsMining() {
+		if err := api.e.StartMining(); err != nil {
 			return [3]string{}, err
 			return [3]string{}, err
 		}
 		}
 	}
 	}
-	work, err := s.agent.GetWork()
+	work, err := api.agent.GetWork()
 	if err != nil {
 	if err != nil {
 		return work, fmt.Errorf("mining not ready: %v", err)
 		return work, fmt.Errorf("mining not ready: %v", err)
 	}
 	}
@@ -116,8 +116,8 @@ func (s *PublicMinerAPI) GetWork() ([3]string, error) {
 // SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined
 // SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined
 // hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which
 // hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which
 // must be unique between nodes.
 // must be unique between nodes.
-func (s *PublicMinerAPI) SubmitHashrate(hashrate hexutil.Uint64, id common.Hash) bool {
-	s.agent.SubmitHashrate(id, uint64(hashrate))
+func (api *PublicMinerAPI) SubmitHashrate(hashrate hexutil.Uint64, id common.Hash) bool {
+	api.agent.SubmitHashrate(id, uint64(hashrate))
 	return true
 	return true
 }
 }
 
 
@@ -132,47 +132,59 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI {
 	return &PrivateMinerAPI{e: e}
 	return &PrivateMinerAPI{e: e}
 }
 }
 
 
-// Start the miner with the given number of threads. If threads is nil the number of
-// workers started is equal to the number of logical CPU's that are usable by this process.
-func (s *PrivateMinerAPI) Start(threads *int) (bool, error) {
-	var err error
-	if threads == nil {
-		err = s.e.StartMining(runtime.NumCPU())
-	} else {
-		err = s.e.StartMining(*threads)
+// Start the miner with the given number of threads. If threads is nil the number
+// of workers started is equal to the number of logical CPUs that are usable by
+// this process. If mining is already running, this method adjust the number of
+// threads allowed to use.
+func (api *PrivateMinerAPI) Start(threads *int) error {
+	// Set the number of threads if the seal engine supports it
+	if threads != nil {
+		type threaded interface {
+			SetThreads(threads int)
+		}
+		if th, ok := api.e.engine.(threaded); ok {
+			log.Info("Updated mining threads", "threads", *threads)
+			th.SetThreads(*threads)
+		} else {
+			log.Warn("Current seal engine isn't threaded")
+		}
 	}
 	}
-	return err == nil, err
+	// Start the miner and return
+	if !api.e.IsMining() {
+		return api.e.StartMining()
+	}
+	return nil
 }
 }
 
 
 // Stop the miner
 // Stop the miner
-func (s *PrivateMinerAPI) Stop() bool {
-	s.e.StopMining()
+func (api *PrivateMinerAPI) Stop() bool {
+	api.e.StopMining()
 	return true
 	return true
 }
 }
 
 
 // SetExtra sets the extra data string that is included when this miner mines a block.
 // SetExtra sets the extra data string that is included when this miner mines a block.
-func (s *PrivateMinerAPI) SetExtra(extra string) (bool, error) {
-	if err := s.e.Miner().SetExtra([]byte(extra)); err != nil {
+func (api *PrivateMinerAPI) SetExtra(extra string) (bool, error) {
+	if err := api.e.Miner().SetExtra([]byte(extra)); err != nil {
 		return false, err
 		return false, err
 	}
 	}
 	return true, nil
 	return true, nil
 }
 }
 
 
 // SetGasPrice sets the minimum accepted gas price for the miner.
 // SetGasPrice sets the minimum accepted gas price for the miner.
-func (s *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
-	s.e.Miner().SetGasPrice((*big.Int)(&gasPrice))
+func (api *PrivateMinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
+	api.e.Miner().SetGasPrice((*big.Int)(&gasPrice))
 	return true
 	return true
 }
 }
 
 
 // SetEtherbase sets the etherbase of the miner
 // SetEtherbase sets the etherbase of the miner
-func (s *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool {
-	s.e.SetEtherbase(etherbase)
+func (api *PrivateMinerAPI) SetEtherbase(etherbase common.Address) bool {
+	api.e.SetEtherbase(etherbase)
 	return true
 	return true
 }
 }
 
 
 // GetHashrate returns the current hashrate of the miner.
 // GetHashrate returns the current hashrate of the miner.
-func (s *PrivateMinerAPI) GetHashrate() uint64 {
-	return uint64(s.e.miner.HashRate())
+func (api *PrivateMinerAPI) GetHashrate() uint64 {
+	return uint64(api.e.miner.HashRate())
 }
 }
 
 
 // PrivateAdminAPI is the collection of Etheruem full node-related APIs
 // PrivateAdminAPI is the collection of Etheruem full node-related APIs
@@ -321,7 +333,7 @@ type TraceArgs struct {
 	Timeout *string
 	Timeout *string
 }
 }
 
 
-// TraceBlock processes the given block's RLP but does not import the block in to
+// TraceBlock processes the given block'api RLP but does not import the block in to
 // the chain.
 // the chain.
 func (api *PrivateDebugAPI) TraceBlock(blockRlp []byte, config *vm.LogConfig) BlockTraceResult {
 func (api *PrivateDebugAPI) TraceBlock(blockRlp []byte, config *vm.LogConfig) BlockTraceResult {
 	var block types.Block
 	var block types.Block
@@ -338,7 +350,7 @@ func (api *PrivateDebugAPI) TraceBlock(blockRlp []byte, config *vm.LogConfig) Bl
 	}
 	}
 }
 }
 
 
-// TraceBlockFromFile loads the block's RLP from the given file name and attempts to
+// TraceBlockFromFile loads the block'api RLP from the given file name and attempts to
 // process it but does not import the block in to the chain.
 // process it but does not import the block in to the chain.
 func (api *PrivateDebugAPI) TraceBlockFromFile(file string, config *vm.LogConfig) BlockTraceResult {
 func (api *PrivateDebugAPI) TraceBlockFromFile(file string, config *vm.LogConfig) BlockTraceResult {
 	blockRlp, err := ioutil.ReadFile(file)
 	blockRlp, err := ioutil.ReadFile(file)
@@ -395,8 +407,7 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, logConfig *vm.LogConf
 		Debug:  true,
 		Debug:  true,
 		Tracer: structLogger,
 		Tracer: structLogger,
 	}
 	}
-
-	if err := core.ValidateHeader(api.config, blockchain.AuxValidator(), block.Header(), blockchain.GetHeader(block.ParentHash(), block.NumberU64()-1), true, false); err != nil {
+	if err := api.eth.engine.VerifyHeader(blockchain, block.Header(), true); err != nil {
 		return false, structLogger.StructLogs(), err
 		return false, structLogger.StructLogs(), err
 	}
 	}
 	statedb, err := blockchain.StateAt(blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1).Root())
 	statedb, err := blockchain.StateAt(blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1).Root())

+ 24 - 25
eth/backend.go

@@ -22,10 +22,11 @@ import (
 	"math/big"
 	"math/big"
 	"regexp"
 	"regexp"
 	"sync"
 	"sync"
-	"time"
 
 
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
@@ -40,18 +41,9 @@ import (
 	"github.com/ethereum/go-ethereum/node"
 	"github.com/ethereum/go-ethereum/node"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rpc"
 	"github.com/ethereum/go-ethereum/rpc"
 )
 )
 
 
-const (
-	epochLength    = 30000
-	ethashRevision = 23
-
-	autoDAGcheckInterval = 10 * time.Hour
-	autoDAGepochHeight   = epochLength / 2
-)
-
 var (
 var (
 	datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true}
 	datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true}
 	portInUseErrRE     = regexp.MustCompile("address already in use")
 	portInUseErrRE     = regexp.MustCompile("address already in use")
@@ -124,7 +116,7 @@ type Ethereum struct {
 	chainDb ethdb.Database // Block chain database
 	chainDb ethdb.Database // Block chain database
 
 
 	eventMux       *event.TypeMux
 	eventMux       *event.TypeMux
-	pow            pow.PoW
+	engine         consensus.Engine
 	accountManager *accounts.Manager
 	accountManager *accounts.Manager
 
 
 	ApiBackend *EthApiBackend
 	ApiBackend *EthApiBackend
@@ -163,7 +155,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 		chainConfig:    chainConfig,
 		chainConfig:    chainConfig,
 		eventMux:       ctx.EventMux,
 		eventMux:       ctx.EventMux,
 		accountManager: ctx.AccountManager,
 		accountManager: ctx.AccountManager,
-		pow:            CreatePoW(ctx, config),
+		engine:         CreateConsensusEngine(ctx, config, chainConfig, chainDb),
 		shutdownChan:   make(chan bool),
 		shutdownChan:   make(chan bool),
 		stopDbUpgrade:  stopDbUpgrade,
 		stopDbUpgrade:  stopDbUpgrade,
 		netVersionId:   config.NetworkId,
 		netVersionId:   config.NetworkId,
@@ -186,7 +178,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 	}
 	}
 
 
 	vmConfig := vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
 	vmConfig := vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
-	eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.eventMux, vmConfig)
+	eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.engine, eth.eventMux, vmConfig)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -211,10 +203,11 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
 		}
 		}
 	}
 	}
 
 
-	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.FastSync, config.NetworkId, maxPeers, eth.eventMux, eth.txPool, eth.pow, eth.blockchain, chainDb); err != nil {
+	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.FastSync, config.NetworkId, maxPeers, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.pow)
+
+	eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine)
 	eth.miner.SetGasPrice(config.GasPrice)
 	eth.miner.SetGasPrice(config.GasPrice)
 	eth.miner.SetExtra(config.ExtraData)
 	eth.miner.SetExtra(config.ExtraData)
 
 
@@ -241,20 +234,20 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data
 	return db, err
 	return db, err
 }
 }
 
 
-// CreatePoW creates the required type of PoW instance for an Ethereum service
-func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
+// CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service
+func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig *params.ChainConfig, db ethdb.Database) consensus.Engine {
 	switch {
 	switch {
 	case config.PowFake:
 	case config.PowFake:
 		log.Warn("Ethash used in fake mode")
 		log.Warn("Ethash used in fake mode")
-		return pow.FakePow{}
+		return ethash.NewFaker()
 	case config.PowTest:
 	case config.PowTest:
 		log.Warn("Ethash used in test mode")
 		log.Warn("Ethash used in test mode")
-		return pow.NewTestEthash()
+		return ethash.NewTester()
 	case config.PowShared:
 	case config.PowShared:
 		log.Warn("Ethash used in shared mode")
 		log.Warn("Ethash used in shared mode")
-		return pow.NewSharedEthash()
+		return ethash.NewShared()
 	default:
 	default:
-		return pow.NewFullEthash(ctx.ResolvePath(config.EthashCacheDir), config.EthashCachesInMem, config.EthashCachesOnDisk,
+		return ethash.New(ctx.ResolvePath(config.EthashCacheDir), config.EthashCachesInMem, config.EthashCachesOnDisk,
 			config.EthashDatasetDir, config.EthashDatasetsInMem, config.EthashDatasetsOnDisk)
 			config.EthashDatasetDir, config.EthashDatasetsInMem, config.EthashDatasetsOnDisk)
 	}
 	}
 }
 }
@@ -262,7 +255,13 @@ func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
 // APIs returns the collection of RPC services the ethereum package offers.
 // APIs returns the collection of RPC services the ethereum package offers.
 // NOTE, some of these services probably need to be moved to somewhere else.
 // NOTE, some of these services probably need to be moved to somewhere else.
 func (s *Ethereum) APIs() []rpc.API {
 func (s *Ethereum) APIs() []rpc.API {
-	return append(ethapi.GetAPIs(s.ApiBackend, s.solcPath), []rpc.API{
+	apis := ethapi.GetAPIs(s.ApiBackend, s.solcPath)
+
+	// Append any APIs exposed explicitly by the consensus engine
+	apis = append(apis, s.engine.APIs(s.BlockChain())...)
+
+	// Append all the local APIs and return
+	return append(apis, []rpc.API{
 		{
 		{
 			Namespace: "eth",
 			Namespace: "eth",
 			Version:   "1.0",
 			Version:   "1.0",
@@ -332,13 +331,13 @@ func (self *Ethereum) SetEtherbase(etherbase common.Address) {
 	self.miner.SetEtherbase(etherbase)
 	self.miner.SetEtherbase(etherbase)
 }
 }
 
 
-func (s *Ethereum) StartMining(threads int) error {
+func (s *Ethereum) StartMining() error {
 	eb, err := s.Etherbase()
 	eb, err := s.Etherbase()
 	if err != nil {
 	if err != nil {
 		log.Error("Cannot start mining without etherbase", "err", err)
 		log.Error("Cannot start mining without etherbase", "err", err)
 		return fmt.Errorf("etherbase missing: %v", err)
 		return fmt.Errorf("etherbase missing: %v", err)
 	}
 	}
-	go s.miner.Start(eb, threads)
+	go s.miner.Start(eb)
 	return nil
 	return nil
 }
 }
 
 
@@ -350,7 +349,7 @@ func (s *Ethereum) AccountManager() *accounts.Manager  { return s.accountManager
 func (s *Ethereum) BlockChain() *core.BlockChain       { return s.blockchain }
 func (s *Ethereum) BlockChain() *core.BlockChain       { return s.blockchain }
 func (s *Ethereum) TxPool() *core.TxPool               { return s.txPool }
 func (s *Ethereum) TxPool() *core.TxPool               { return s.txPool }
 func (s *Ethereum) EventMux() *event.TypeMux           { return s.eventMux }
 func (s *Ethereum) EventMux() *event.TypeMux           { return s.eventMux }
-func (s *Ethereum) Pow() pow.PoW                       { return s.pow }
+func (s *Ethereum) Engine() consensus.Engine           { return s.engine }
 func (s *Ethereum) ChainDb() ethdb.Database            { return s.chainDb }
 func (s *Ethereum) ChainDb() ethdb.Database            { return s.chainDb }
 func (s *Ethereum) IsListening() bool                  { return true } // Always listening
 func (s *Ethereum) IsListening() bool                  { return true } // Always listening
 func (s *Ethereum) EthVersion() int                    { return int(s.protocolManager.SubProtocols[0].Version) }
 func (s *Ethereum) EthVersion() int                    { return int(s.protocolManager.SubProtocols[0].Version) }

+ 6 - 6
eth/fetcher/fetcher.go

@@ -52,8 +52,8 @@ type headerRequesterFn func(common.Hash) error
 // bodyRequesterFn is a callback type for sending a body retrieval request.
 // bodyRequesterFn is a callback type for sending a body retrieval request.
 type bodyRequesterFn func([]common.Hash) error
 type bodyRequesterFn func([]common.Hash) error
 
 
-// blockValidatorFn is a callback type to verify a block's header for fast propagation.
-type blockValidatorFn func(block *types.Block, parent *types.Block) error
+// headerVerifierFn is a callback type to verify a block's header for fast propagation.
+type headerVerifierFn func(header *types.Header) error
 
 
 // blockBroadcasterFn is a callback type for broadcasting a block to connected peers.
 // blockBroadcasterFn is a callback type for broadcasting a block to connected peers.
 type blockBroadcasterFn func(block *types.Block, propagate bool)
 type blockBroadcasterFn func(block *types.Block, propagate bool)
@@ -129,7 +129,7 @@ type Fetcher struct {
 
 
 	// Callbacks
 	// Callbacks
 	getBlock       blockRetrievalFn   // Retrieves a block from the local chain
 	getBlock       blockRetrievalFn   // Retrieves a block from the local chain
-	validateBlock  blockValidatorFn   // Checks if a block's headers have a valid proof of work
+	verifyHeader   headerVerifierFn   // Checks if a block's headers have a valid proof of work
 	broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers
 	broadcastBlock blockBroadcasterFn // Broadcasts a block to connected peers
 	chainHeight    chainHeightFn      // Retrieves the current chain's height
 	chainHeight    chainHeightFn      // Retrieves the current chain's height
 	insertChain    chainInsertFn      // Injects a batch of blocks into the chain
 	insertChain    chainInsertFn      // Injects a batch of blocks into the chain
@@ -144,7 +144,7 @@ type Fetcher struct {
 }
 }
 
 
 // New creates a block fetcher to retrieve blocks based on hash announcements.
 // New creates a block fetcher to retrieve blocks based on hash announcements.
-func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertChain chainInsertFn, dropPeer peerDropFn) *Fetcher {
+func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertChain chainInsertFn, dropPeer peerDropFn) *Fetcher {
 	return &Fetcher{
 	return &Fetcher{
 		notify:         make(chan *announce),
 		notify:         make(chan *announce),
 		inject:         make(chan *inject),
 		inject:         make(chan *inject),
@@ -162,7 +162,7 @@ func New(getBlock blockRetrievalFn, validateBlock blockValidatorFn, broadcastBlo
 		queues:         make(map[string]int),
 		queues:         make(map[string]int),
 		queued:         make(map[common.Hash]*inject),
 		queued:         make(map[common.Hash]*inject),
 		getBlock:       getBlock,
 		getBlock:       getBlock,
-		validateBlock:  validateBlock,
+		verifyHeader:   verifyHeader,
 		broadcastBlock: broadcastBlock,
 		broadcastBlock: broadcastBlock,
 		chainHeight:    chainHeight,
 		chainHeight:    chainHeight,
 		insertChain:    insertChain,
 		insertChain:    insertChain,
@@ -648,7 +648,7 @@ func (f *Fetcher) insert(peer string, block *types.Block) {
 			return
 			return
 		}
 		}
 		// Quickly validate the header and propagate the block if it passes
 		// Quickly validate the header and propagate the block if it passes
-		switch err := f.validateBlock(block, parent); err {
+		switch err := f.verifyHeader(block.Header()); err {
 		case nil:
 		case nil:
 			// All ok, quickly propagate to our peers
 			// All ok, quickly propagate to our peers
 			propBroadcastOutTimer.UpdateSince(block.ReceivedAt)
 			propBroadcastOutTimer.UpdateSince(block.ReceivedAt)

+ 3 - 3
eth/fetcher/fetcher_test.go

@@ -91,7 +91,7 @@ func newTester() *fetcherTester {
 		blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis},
 		blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis},
 		drops:  make(map[string]bool),
 		drops:  make(map[string]bool),
 	}
 	}
-	tester.fetcher = New(tester.getBlock, tester.verifyBlock, tester.broadcastBlock, tester.chainHeight, tester.insertChain, tester.dropPeer)
+	tester.fetcher = New(tester.getBlock, tester.verifyHeader, tester.broadcastBlock, tester.chainHeight, tester.insertChain, tester.dropPeer)
 	tester.fetcher.Start()
 	tester.fetcher.Start()
 
 
 	return tester
 	return tester
@@ -105,8 +105,8 @@ func (f *fetcherTester) getBlock(hash common.Hash) *types.Block {
 	return f.blocks[hash]
 	return f.blocks[hash]
 }
 }
 
 
-// verifyBlock is a nop placeholder for the block header verification.
-func (f *fetcherTester) verifyBlock(block *types.Block, parent *types.Block) error {
+// verifyHeader is a nop placeholder for the block header verification.
+func (f *fetcherTester) verifyHeader(header *types.Header) error {
 	return nil
 	return nil
 }
 }
 
 

+ 6 - 5
eth/handler.go

@@ -27,6 +27,8 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
+	"github.com/ethereum/go-ethereum/consensus/misc"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth/downloader"
 	"github.com/ethereum/go-ethereum/eth/downloader"
@@ -37,7 +39,6 @@ import (
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 )
 )
 
 
@@ -97,7 +98,7 @@ type ProtocolManager struct {
 
 
 // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
 // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
 // with the ethereum network.
 // with the ethereum network.
-func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
+func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
 	// Create the protocol manager with the base fields
 	// Create the protocol manager with the base fields
 	manager := &ProtocolManager{
 	manager := &ProtocolManager{
 		networkId:   networkId,
 		networkId:   networkId,
@@ -165,8 +166,8 @@ func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int
 		blockchain.GetTdByHash, blockchain.InsertHeaderChain, manager.insertChain, blockchain.InsertReceiptChain, blockchain.Rollback,
 		blockchain.GetTdByHash, blockchain.InsertHeaderChain, manager.insertChain, blockchain.InsertReceiptChain, blockchain.Rollback,
 		manager.removePeer)
 		manager.removePeer)
 
 
-	validator := func(block *types.Block, parent *types.Block) error {
-		return core.ValidateHeader(config, pow, block.Header(), parent.Header(), true, false)
+	validator := func(header *types.Header) error {
+		return engine.VerifyHeader(blockchain, header, true)
 	}
 	}
 	heighter := func() uint64 {
 	heighter := func() uint64 {
 		return blockchain.CurrentBlock().NumberU64()
 		return blockchain.CurrentBlock().NumberU64()
@@ -448,7 +449,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
 				p.forkDrop = nil
 				p.forkDrop = nil
 
 
 				// Validate the header and either drop the peer or continue
 				// Validate the header and either drop the peer or continue
-				if err := core.ValidateDAOHeaderExtraData(pm.chainconfig, headers[0]); err != nil {
+				if err := misc.VerifyDAOHeaderExtraData(pm.chainconfig, headers[0]); err != nil {
 					p.Log().Debug("Verified to be on the other side of the DAO fork, dropping")
 					p.Log().Debug("Verified to be on the other side of the DAO fork, dropping")
 					return err
 					return err
 				}
 				}

+ 2 - 2
eth/handler_test.go

@@ -24,6 +24,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -34,7 +35,6 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 var bigTxGas = new(big.Int).SetUint64(params.TxGas)
 var bigTxGas = new(big.Int).SetUint64(params.TxGas)
@@ -469,7 +469,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
 	// Create a DAO aware protocol manager
 	// Create a DAO aware protocol manager
 	var (
 	var (
 		evmux         = new(event.TypeMux)
 		evmux         = new(event.TypeMux)
-		pow           = new(pow.FakePow)
+		pow           = ethash.NewFaker()
 		db, _         = ethdb.NewMemDatabase()
 		db, _         = ethdb.NewMemDatabase()
 		config        = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
 		config        = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
 		gspec         = &core.Genesis{Config: config}
 		gspec         = &core.Genesis{Config: config}

+ 7 - 7
eth/helper_test.go

@@ -28,6 +28,7 @@ import (
 	"testing"
 	"testing"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
@@ -37,7 +38,6 @@ import (
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 var (
 var (
@@ -50,22 +50,22 @@ var (
 // channels for different events.
 // channels for different events.
 func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) {
 func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) {
 	var (
 	var (
-		evmux = new(event.TypeMux)
-		pow   = new(pow.FakePow)
-		db, _ = ethdb.NewMemDatabase()
-		gspec = &core.Genesis{
+		evmux  = new(event.TypeMux)
+		engine = ethash.NewFaker()
+		db, _  = ethdb.NewMemDatabase()
+		gspec  = &core.Genesis{
 			Config: params.TestChainConfig,
 			Config: params.TestChainConfig,
 			Alloc:  core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
 			Alloc:  core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
 		}
 		}
 		genesis       = gspec.MustCommit(db)
 		genesis       = gspec.MustCommit(db)
-		blockchain, _ = core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
+		blockchain, _ = core.NewBlockChain(db, gspec.Config, engine, evmux, vm.Config{})
 	)
 	)
 	chain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
 	chain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
 	if _, err := blockchain.InsertChain(chain); err != nil {
 	if _, err := blockchain.InsertChain(chain); err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
 
 
-	pm, err := NewProtocolManager(gspec.Config, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
+	pm, err := NewProtocolManager(gspec.Config, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, engine, blockchain, db)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 2 - 2
internal/ethapi/api.go

@@ -31,6 +31,7 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
@@ -39,7 +40,6 @@ import (
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rpc"
 	"github.com/ethereum/go-ethereum/rpc"
 	"github.com/syndtr/goleveldb/leveldb"
 	"github.com/syndtr/goleveldb/leveldb"
@@ -1378,7 +1378,7 @@ func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string,
 	if block == nil {
 	if block == nil {
 		return "", fmt.Errorf("block #%d not found", number)
 		return "", fmt.Errorf("block #%d not found", number)
 	}
 	}
-	return fmt.Sprintf("0x%x", pow.EthashSeedHash(number)), nil
+	return fmt.Sprintf("0x%x", ethash.SeedHash(number)), nil
 }
 }
 
 
 // PrivateDebugAPI is the collection of Etheruem APIs exposed over the private
 // PrivateDebugAPI is the collection of Etheruem APIs exposed over the private

+ 5 - 7
les/backend.go

@@ -25,6 +25,7 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/compiler"
 	"github.com/ethereum/go-ethereum/common/compiler"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/common/hexutil"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth"
 	"github.com/ethereum/go-ethereum/eth"
@@ -39,7 +40,6 @@ import (
 	"github.com/ethereum/go-ethereum/node"
 	"github.com/ethereum/go-ethereum/node"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	rpc "github.com/ethereum/go-ethereum/rpc"
 	rpc "github.com/ethereum/go-ethereum/rpc"
 )
 )
 
 
@@ -59,7 +59,7 @@ type LightEthereum struct {
 	ApiBackend *LesApiBackend
 	ApiBackend *LesApiBackend
 
 
 	eventMux       *event.TypeMux
 	eventMux       *event.TypeMux
-	pow            pow.PoW
+	engine         consensus.Engine
 	accountManager *accounts.Manager
 	accountManager *accounts.Manager
 	solcPath       string
 	solcPath       string
 	solc           *compiler.Solidity
 	solc           *compiler.Solidity
@@ -88,14 +88,12 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
 		chainConfig:    chainConfig,
 		chainConfig:    chainConfig,
 		eventMux:       ctx.EventMux,
 		eventMux:       ctx.EventMux,
 		accountManager: ctx.AccountManager,
 		accountManager: ctx.AccountManager,
-		pow:            eth.CreatePoW(ctx, config),
+		engine:         eth.CreateConsensusEngine(ctx, config, chainConfig, chainDb),
 		shutdownChan:   make(chan bool),
 		shutdownChan:   make(chan bool),
 		netVersionId:   config.NetworkId,
 		netVersionId:   config.NetworkId,
 		solcPath:       config.SolcPath,
 		solcPath:       config.SolcPath,
 	}
 	}
-
-	eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
-	if err != nil {
+	if eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.engine, eth.eventMux); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	// Rewind the chain in case of an incompatible config upgrade.
 	// Rewind the chain in case of an incompatible config upgrade.
@@ -106,7 +104,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
 	}
 	}
 
 
 	eth.txPool = light.NewTxPool(eth.chainConfig, eth.eventMux, eth.blockchain, eth.relay)
 	eth.txPool = light.NewTxPool(eth.chainConfig, eth.eventMux, eth.blockchain, eth.relay)
-	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.LightMode, config.NetworkId, eth.eventMux, eth.pow, eth.blockchain, nil, chainDb, odr, relay); err != nil {
+	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.LightMode, config.NetworkId, eth.eventMux, eth.engine, eth.blockchain, nil, chainDb, odr, relay); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	relay.ps = eth.protocolManager.peers
 	relay.ps = eth.protocolManager.peers

+ 2 - 2
les/handler.go

@@ -27,6 +27,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -39,7 +40,6 @@ import (
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/p2p/discv5"
 	"github.com/ethereum/go-ethereum/p2p/discv5"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/trie"
 	"github.com/ethereum/go-ethereum/trie"
 )
 )
@@ -128,7 +128,7 @@ type ProtocolManager struct {
 
 
 // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
 // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
 // with the ethereum network.
 // with the ethereum network.
-func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, pow pow.PoW, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
+func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, engine consensus.Engine, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
 	// Create the protocol manager with the base fields
 	// Create the protocol manager with the base fields
 	manager := &ProtocolManager{
 	manager := &ProtocolManager{
 		lightSync:   lightSync,
 		lightSync:   lightSync,

+ 8 - 8
les/helper_test.go

@@ -28,6 +28,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
@@ -39,7 +40,6 @@ import (
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p"
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/p2p/discover"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 var (
 var (
@@ -134,10 +134,10 @@ func testRCL() RequestCostList {
 // channels for different events.
 // channels for different events.
 func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen)) (*ProtocolManager, ethdb.Database, *LesOdr, error) {
 func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen)) (*ProtocolManager, ethdb.Database, *LesOdr, error) {
 	var (
 	var (
-		evmux = new(event.TypeMux)
-		pow   = new(pow.FakePow)
-		db, _ = ethdb.NewMemDatabase()
-		gspec = core.Genesis{
+		evmux  = new(event.TypeMux)
+		engine = ethash.NewFaker()
+		db, _  = ethdb.NewMemDatabase()
+		gspec  = core.Genesis{
 			Config: params.TestChainConfig,
 			Config: params.TestChainConfig,
 			Alloc:  core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
 			Alloc:  core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
 		}
 		}
@@ -148,9 +148,9 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
 
 
 	if lightSync {
 	if lightSync {
 		odr = NewLesOdr(db)
 		odr = NewLesOdr(db)
-		chain, _ = light.NewLightChain(odr, gspec.Config, pow, evmux)
+		chain, _ = light.NewLightChain(odr, gspec.Config, engine, evmux)
 	} else {
 	} else {
-		blockchain, _ := core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
+		blockchain, _ := core.NewBlockChain(db, gspec.Config, engine, evmux, vm.Config{})
 		gchain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
 		gchain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
 		if _, err := blockchain.InsertChain(gchain); err != nil {
 		if _, err := blockchain.InsertChain(gchain); err != nil {
 			panic(err)
 			panic(err)
@@ -158,7 +158,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
 		chain = blockchain
 		chain = blockchain
 	}
 	}
 
 
-	pm, err := NewProtocolManager(gspec.Config, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil)
+	pm, err := NewProtocolManager(gspec.Config, lightSync, NetworkId, evmux, engine, chain, nil, db, odr, nil)
 	if err != nil {
 	if err != nil {
 		return nil, nil, nil, err
 		return nil, nil, nil, err
 	}
 	}

+ 1 - 1
les/server.go

@@ -45,7 +45,7 @@ type LesServer struct {
 }
 }
 
 
 func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
 func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
-	pm, err := NewProtocolManager(eth.BlockChain().Config(), false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
+	pm, err := NewProtocolManager(eth.BlockChain().Config(), false, config.NetworkId, eth.EventMux(), eth.Engine(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 5 - 27
light/lightchain.go

@@ -24,13 +24,13 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/hashicorp/golang-lru"
 	"github.com/hashicorp/golang-lru"
 )
 )
@@ -64,14 +64,13 @@ type LightChain struct {
 	procInterrupt int32 // interrupt signaler for block processing
 	procInterrupt int32 // interrupt signaler for block processing
 	wg            sync.WaitGroup
 	wg            sync.WaitGroup
 
 
-	pow       pow.PoW
-	validator core.HeaderValidator
+	engine consensus.Engine
 }
 }
 
 
 // NewLightChain returns a fully initialised light chain using information
 // NewLightChain returns a fully initialised light chain using information
 // available in the database. It initialises the default Ethereum header
 // available in the database. It initialises the default Ethereum header
 // validator.
 // validator.
-func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*LightChain, error) {
+func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, mux *event.TypeMux) (*LightChain, error) {
 	bodyCache, _ := lru.New(bodyCacheLimit)
 	bodyCache, _ := lru.New(bodyCacheLimit)
 	bodyRLPCache, _ := lru.New(bodyCacheLimit)
 	bodyRLPCache, _ := lru.New(bodyCacheLimit)
 	blockCache, _ := lru.New(blockCacheLimit)
 	blockCache, _ := lru.New(blockCacheLimit)
@@ -84,21 +83,17 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
 		bodyCache:    bodyCache,
 		bodyCache:    bodyCache,
 		bodyRLPCache: bodyRLPCache,
 		bodyRLPCache: bodyRLPCache,
 		blockCache:   blockCache,
 		blockCache:   blockCache,
-		pow:          pow,
+		engine:       engine,
 	}
 	}
-
 	var err error
 	var err error
-	bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.Validator, bc.getProcInterrupt)
-	bc.SetValidator(core.NewHeaderValidator(config, bc.hc, pow))
+	bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-
 	bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
 	bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
 	if bc.genesisBlock == nil {
 	if bc.genesisBlock == nil {
 		return nil, core.ErrNoGenesis
 		return nil, core.ErrNoGenesis
 	}
 	}
-
 	if bc.genesisBlock.Hash() == params.MainNetGenesisHash {
 	if bc.genesisBlock.Hash() == params.MainNetGenesisHash {
 		// add trusted CHT
 		// add trusted CHT
 		WriteTrustedCht(bc.chainDb, TrustedCht{Number: 805, Root: common.HexToHash("85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f")})
 		WriteTrustedCht(bc.chainDb, TrustedCht{Number: 805, Root: common.HexToHash("85e4286fe0a730390245c49de8476977afdae0eb5530b277f62a52b12313d50f")})
@@ -145,9 +140,6 @@ func (self *LightChain) loadLastState() error {
 	headerTd := self.GetTd(header.Hash(), header.Number.Uint64())
 	headerTd := self.GetTd(header.Hash(), header.Number.Uint64())
 	log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd)
 	log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd)
 
 
-	// Try to be smart and issue a pow verification for the head to pre-generate caches
-	go self.pow.Verify(types.NewBlockWithHeader(header))
-
 	return nil
 	return nil
 }
 }
 
 
@@ -188,20 +180,6 @@ func (self *LightChain) Status() (td *big.Int, currentBlock common.Hash, genesis
 	return self.GetTd(hash, header.Number.Uint64()), hash, self.genesisBlock.Hash()
 	return self.GetTd(hash, header.Number.Uint64()), hash, self.genesisBlock.Hash()
 }
 }
 
 
-// SetValidator sets the validator which is used to validate incoming headers.
-func (self *LightChain) SetValidator(validator core.HeaderValidator) {
-	self.procmu.Lock()
-	defer self.procmu.Unlock()
-	self.validator = validator
-}
-
-// Validator returns the current header validator.
-func (self *LightChain) Validator() core.HeaderValidator {
-	self.procmu.RLock()
-	defer self.procmu.RUnlock()
-	return self.validator
-}
-
 // State returns a new mutable state based on the current HEAD block.
 // State returns a new mutable state based on the current HEAD block.
 func (self *LightChain) State() *LightState {
 func (self *LightChain) State() *LightState {
 	return NewLightState(StateTrieID(self.hc.CurrentHeader()), self.odr)
 	return NewLightState(StateTrieID(self.hc.CurrentHeader()), self.odr)

+ 13 - 21
light/lightchain_test.go

@@ -23,12 +23,12 @@ import (
 	"testing"
 	"testing"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 // So we can deterministically seed different blockchains
 // So we can deterministically seed different blockchains
@@ -49,18 +49,15 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
 	return headers
 	return headers
 }
 }
 
 
-func testChainConfig() *params.ChainConfig {
-	return &params.ChainConfig{HomesteadBlock: big.NewInt(0)}
-}
-
 // newCanonical creates a chain database, and injects a deterministic canonical
 // newCanonical creates a chain database, and injects a deterministic canonical
 // chain. Depending on the full flag, if creates either a full block chain or a
 // chain. Depending on the full flag, if creates either a full block chain or a
 // header only chain.
 // header only chain.
 func newCanonical(n int) (ethdb.Database, *LightChain, error) {
 func newCanonical(n int) (ethdb.Database, *LightChain, error) {
 	db, _ := ethdb.NewMemDatabase()
 	db, _ := ethdb.NewMemDatabase()
-	gspec := core.Genesis{Config: testChainConfig()}
+	gspec := core.Genesis{Config: params.TestChainConfig}
 	genesis := gspec.MustCommit(db)
 	genesis := gspec.MustCommit(db)
-	blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.FakePow{}, new(event.TypeMux))
+	blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFaker(), new(event.TypeMux))
+
 	// Create and inject the requested chain
 	// Create and inject the requested chain
 	if n == 0 {
 	if n == 0 {
 		return db, blockchain, nil
 		return db, blockchain, nil
@@ -76,14 +73,13 @@ func newTestLightChain() *LightChain {
 	db, _ := ethdb.NewMemDatabase()
 	db, _ := ethdb.NewMemDatabase()
 	gspec := &core.Genesis{
 	gspec := &core.Genesis{
 		Difficulty: big.NewInt(1),
 		Difficulty: big.NewInt(1),
-		Config:     testChainConfig(),
+		Config:     params.TestChainConfig,
 	}
 	}
 	gspec.MustCommit(db)
 	gspec.MustCommit(db)
-	lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
+	lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), new(event.TypeMux))
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
-	lc.SetValidator(bproc{})
 	return lc
 	return lc
 }
 }
 
 
@@ -130,17 +126,17 @@ func printChain(bc *LightChain) {
 
 
 // testHeaderChainImport tries to process a chain of header, writing them into
 // testHeaderChainImport tries to process a chain of header, writing them into
 // the database if successful.
 // the database if successful.
-func testHeaderChainImport(chain []*types.Header, LightChain *LightChain) error {
+func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error {
 	for _, header := range chain {
 	for _, header := range chain {
 		// Try and validate the header
 		// Try and validate the header
-		if err := LightChain.Validator().ValidateHeader(header, LightChain.GetHeaderByHash(header.ParentHash), false); err != nil {
+		if err := lightchain.engine.VerifyHeader(lightchain.hc, header, true); err != nil {
 			return err
 			return err
 		}
 		}
 		// Manually insert the header into the database, but don't reorganize (allows subsequent testing)
 		// Manually insert the header into the database, but don't reorganize (allows subsequent testing)
-		LightChain.mu.Lock()
-		core.WriteTd(LightChain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, LightChain.GetTdByHash(header.ParentHash)))
-		core.WriteHeader(LightChain.chainDb, header)
-		LightChain.mu.Unlock()
+		lightchain.mu.Lock()
+		core.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, lightchain.GetTdByHash(header.ParentHash)))
+		core.WriteHeader(lightchain.chainDb, header)
+		lightchain.mu.Unlock()
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -257,10 +253,6 @@ func TestBrokenHeaderChain(t *testing.T) {
 	}
 	}
 }
 }
 
 
-type bproc struct{}
-
-func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return nil }
-
 func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {
 func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {
 	var chain []*types.Header
 	var chain []*types.Header
 	for i, difficulty := range d {
 	for i, difficulty := range d {
@@ -359,7 +351,7 @@ func TestReorgBadHeaderHashes(t *testing.T) {
 	defer func() { delete(core.BadHashes, headers[3].Hash()) }()
 	defer func() { delete(core.BadHashes, headers[3].Hash()) }()
 
 
 	// Create a new LightChain and check that it rolled back the state.
 	// Create a new LightChain and check that it rolled back the state.
-	ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, testChainConfig(), pow.FakePow{}, new(event.TypeMux))
+	ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux))
 	if err != nil {
 	if err != nil {
 		t.Fatalf("failed to create new chain manager: %v", err)
 		t.Fatalf("failed to create new chain manager: %v", err)
 	}
 	}

+ 4 - 7
light/odr_test.go

@@ -26,6 +26,7 @@ import (
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -34,7 +35,6 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/trie"
 	"github.com/ethereum/go-ethereum/trie"
 )
 )
@@ -248,7 +248,6 @@ func testChainGen(i int, block *core.BlockGen) {
 func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
 func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
 	var (
 	var (
 		evmux   = new(event.TypeMux)
 		evmux   = new(event.TypeMux)
-		pow     = new(pow.FakePow)
 		sdb, _  = ethdb.NewMemDatabase()
 		sdb, _  = ethdb.NewMemDatabase()
 		ldb, _  = ethdb.NewMemDatabase()
 		ldb, _  = ethdb.NewMemDatabase()
 		gspec   = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
 		gspec   = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
@@ -256,16 +255,14 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
 	)
 	)
 	gspec.MustCommit(ldb)
 	gspec.MustCommit(ldb)
 	// Assemble the test environment
 	// Assemble the test environment
-	blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
-	chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}
-	gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, 4, testChainGen)
+	blockchain, _ := core.NewBlockChain(sdb, params.TestChainConfig, ethash.NewFullFaker(), evmux, vm.Config{})
+	gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, sdb, 4, testChainGen)
 	if _, err := blockchain.InsertChain(gchain); err != nil {
 	if _, err := blockchain.InsertChain(gchain); err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
 
 
 	odr := &testOdr{sdb: sdb, ldb: ldb}
 	odr := &testOdr{sdb: sdb, ldb: ldb}
-	lightchain, _ := NewLightChain(odr, testChainConfig(), pow, evmux)
-	lightchain.SetValidator(bproc{})
+	lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), evmux)
 	headers := make([]*types.Header, len(gchain))
 	headers := make([]*types.Header, len(gchain))
 	for i, block := range gchain {
 	for i, block := range gchain {
 		headers[i] = block.Header()
 		headers[i] = block.Header()

+ 5 - 8
light/txpool_test.go

@@ -24,13 +24,13 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 type testTxRelay struct {
 type testTxRelay struct {
@@ -83,7 +83,6 @@ func TestTxPool(t *testing.T) {
 
 
 	var (
 	var (
 		evmux   = new(event.TypeMux)
 		evmux   = new(event.TypeMux)
-		pow     = new(pow.FakePow)
 		sdb, _  = ethdb.NewMemDatabase()
 		sdb, _  = ethdb.NewMemDatabase()
 		ldb, _  = ethdb.NewMemDatabase()
 		ldb, _  = ethdb.NewMemDatabase()
 		gspec   = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
 		gspec   = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
@@ -91,9 +90,8 @@ func TestTxPool(t *testing.T) {
 	)
 	)
 	gspec.MustCommit(ldb)
 	gspec.MustCommit(ldb)
 	// Assemble the test environment
 	// Assemble the test environment
-	blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
-	chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}
-	gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
+	blockchain, _ := core.NewBlockChain(sdb, params.TestChainConfig, ethash.NewFullFaker(), evmux, vm.Config{})
+	gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
 	if _, err := blockchain.InsertChain(gchain); err != nil {
 	if _, err := blockchain.InsertChain(gchain); err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
@@ -104,10 +102,9 @@ func TestTxPool(t *testing.T) {
 		discard: make(chan int, 1),
 		discard: make(chan int, 1),
 		mined:   make(chan int, 1),
 		mined:   make(chan int, 1),
 	}
 	}
-	lightchain, _ := NewLightChain(odr, testChainConfig(), pow, evmux)
-	lightchain.SetValidator(bproc{})
+	lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), evmux)
 	txPermanent = 50
 	txPermanent = 50
-	pool := NewTxPool(testChainConfig(), evmux, lightchain, relay)
+	pool := NewTxPool(params.TestChainConfig, evmux, lightchain, relay)
 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
 	defer cancel()
 	defer cancel()
 
 

+ 3 - 3
log/format.go

@@ -133,10 +133,10 @@ func TerminalFormat(usecolor bool) Format {
 			}
 			}
 		}
 		}
 		// try to justify the log output for short messages
 		// try to justify the log output for short messages
-		if len(r.Ctx) > 0 && len(r.Msg) < termMsgJust {
-			b.Write(bytes.Repeat([]byte{' '}, termMsgJust-len(r.Msg)))
+		length := utf8.RuneCountInString(r.Msg)
+		if len(r.Ctx) > 0 && length < termMsgJust {
+			b.Write(bytes.Repeat([]byte{' '}, termMsgJust-length))
 		}
 		}
-
 		// print the keys logfmt style
 		// print the keys logfmt style
 		logfmt(b, r.Ctx, color, true)
 		logfmt(b, r.Ctx, color, true)
 		return b.Bytes()
 		return b.Bytes()

+ 20 - 27
miner/agent.go

@@ -17,56 +17,49 @@
 package miner
 package miner
 
 
 import (
 import (
-	"fmt"
 	"sync"
 	"sync"
 
 
 	"sync/atomic"
 	"sync/atomic"
 
 
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 type CpuAgent struct {
 type CpuAgent struct {
 	mu sync.Mutex
 	mu sync.Mutex
 
 
 	workCh        chan *Work
 	workCh        chan *Work
-	quit          chan struct{}
+	stop          chan struct{}
 	quitCurrentOp chan struct{}
 	quitCurrentOp chan struct{}
 	returnCh      chan<- *Result
 	returnCh      chan<- *Result
 
 
-	index int
-	pow   pow.PoW
+	chain  consensus.ChainReader
+	engine consensus.Engine
 
 
 	isMining int32 // isMining indicates whether the agent is currently mining
 	isMining int32 // isMining indicates whether the agent is currently mining
 }
 }
 
 
-func NewCpuAgent(index int, pow pow.PoW) *CpuAgent {
+func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine) *CpuAgent {
 	miner := &CpuAgent{
 	miner := &CpuAgent{
-		pow:    pow,
-		index:  index,
-		quit:   make(chan struct{}),
+		chain:  chain,
+		engine: engine,
+		stop:   make(chan struct{}, 1),
 		workCh: make(chan *Work, 1),
 		workCh: make(chan *Work, 1),
 	}
 	}
-
 	return miner
 	return miner
 }
 }
 
 
 func (self *CpuAgent) Work() chan<- *Work            { return self.workCh }
 func (self *CpuAgent) Work() chan<- *Work            { return self.workCh }
-func (self *CpuAgent) Pow() pow.PoW                  { return self.pow }
 func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { self.returnCh = ch }
 func (self *CpuAgent) SetReturnCh(ch chan<- *Result) { self.returnCh = ch }
 
 
 func (self *CpuAgent) Stop() {
 func (self *CpuAgent) Stop() {
-	close(self.quit)
+	self.stop <- struct{}{}
 }
 }
 
 
 func (self *CpuAgent) Start() {
 func (self *CpuAgent) Start() {
-
 	if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) {
 	if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) {
 		return // agent already started
 		return // agent already started
 	}
 	}
-
 	go self.update()
 	go self.update()
 }
 }
 
 
@@ -82,7 +75,7 @@ out:
 			self.quitCurrentOp = make(chan struct{})
 			self.quitCurrentOp = make(chan struct{})
 			go self.mine(work, self.quitCurrentOp)
 			go self.mine(work, self.quitCurrentOp)
 			self.mu.Unlock()
 			self.mu.Unlock()
-		case <-self.quit:
+		case <-self.stop:
 			self.mu.Lock()
 			self.mu.Lock()
 			if self.quitCurrentOp != nil {
 			if self.quitCurrentOp != nil {
 				close(self.quitCurrentOp)
 				close(self.quitCurrentOp)
@@ -99,27 +92,27 @@ done:
 		select {
 		select {
 		case <-self.workCh:
 		case <-self.workCh:
 		default:
 		default:
-			close(self.workCh)
 			break done
 			break done
 		}
 		}
 	}
 	}
-
 	atomic.StoreInt32(&self.isMining, 0)
 	atomic.StoreInt32(&self.isMining, 0)
 }
 }
 
 
 func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
 func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
-	log.Debug(fmt.Sprintf("(re)started agent[%d]. mining...\n", self.index))
-
-	// Mine
-	nonce, mixDigest := self.pow.Search(work.Block, stop)
-	if nonce != 0 {
-		block := work.Block.WithMiningResult(types.EncodeNonce(nonce), common.BytesToHash(mixDigest))
-		self.returnCh <- &Result{work, block}
+	if result, err := self.engine.Seal(self.chain, work.Block, stop); result != nil {
+		log.Info("Successfully sealed new block", "number", result.Number(), "hash", result.Hash())
+		self.returnCh <- &Result{work, result}
 	} else {
 	} else {
+		if err != nil {
+			log.Warn("Block sealing failed", "err", err)
+		}
 		self.returnCh <- nil
 		self.returnCh <- nil
 	}
 	}
 }
 }
 
 
 func (self *CpuAgent) GetHashRate() int64 {
 func (self *CpuAgent) GetHashRate() int64 {
-	return int64(self.pow.Hashrate())
+	if pow, ok := self.engine.(consensus.PoW); ok {
+		return int64(pow.Hashrate())
+	}
+	return 0
 }
 }

+ 14 - 17
miner/miner.go

@@ -24,6 +24,7 @@ import (
 
 
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -32,7 +33,6 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 // Backend wraps all methods required for mining.
 // Backend wraps all methods required for mining.
@@ -49,24 +49,24 @@ type Miner struct {
 
 
 	worker *worker
 	worker *worker
 
 
-	threads  int
 	coinbase common.Address
 	coinbase common.Address
 	mining   int32
 	mining   int32
 	eth      Backend
 	eth      Backend
-	pow      pow.PoW
+	engine   consensus.Engine
 
 
 	canStart    int32 // can start indicates whether we can start the mining operation
 	canStart    int32 // can start indicates whether we can start the mining operation
 	shouldStart int32 // should start indicates whether we should start after sync
 	shouldStart int32 // should start indicates whether we should start after sync
 }
 }
 
 
-func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner {
+func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine) *Miner {
 	miner := &Miner{
 	miner := &Miner{
 		eth:      eth,
 		eth:      eth,
 		mux:      mux,
 		mux:      mux,
-		pow:      pow,
-		worker:   newWorker(config, common.Address{}, eth, mux),
+		engine:   engine,
+		worker:   newWorker(config, engine, common.Address{}, eth, mux),
 		canStart: 1,
 		canStart: 1,
 	}
 	}
+	miner.Register(NewCpuAgent(eth.BlockChain(), engine))
 	go miner.update()
 	go miner.update()
 
 
 	return miner
 	return miner
@@ -86,7 +86,7 @@ out:
 			if self.Mining() {
 			if self.Mining() {
 				self.Stop()
 				self.Stop()
 				atomic.StoreInt32(&self.shouldStart, 1)
 				atomic.StoreInt32(&self.shouldStart, 1)
-				log.Info(fmt.Sprint("Mining operation aborted due to sync operation"))
+				log.Info("Mining aborted due to sync")
 			}
 			}
 		case downloader.DoneEvent, downloader.FailedEvent:
 		case downloader.DoneEvent, downloader.FailedEvent:
 			shouldStart := atomic.LoadInt32(&self.shouldStart) == 1
 			shouldStart := atomic.LoadInt32(&self.shouldStart) == 1
@@ -94,7 +94,7 @@ out:
 			atomic.StoreInt32(&self.canStart, 1)
 			atomic.StoreInt32(&self.canStart, 1)
 			atomic.StoreInt32(&self.shouldStart, 0)
 			atomic.StoreInt32(&self.shouldStart, 0)
 			if shouldStart {
 			if shouldStart {
-				self.Start(self.coinbase, self.threads)
+				self.Start(self.coinbase)
 			}
 			}
 			// unsubscribe. we're only interested in this event once
 			// unsubscribe. we're only interested in this event once
 			events.Unsubscribe()
 			events.Unsubscribe()
@@ -116,23 +116,18 @@ func (m *Miner) SetGasPrice(price *big.Int) {
 	m.worker.setGasPrice(price)
 	m.worker.setGasPrice(price)
 }
 }
 
 
-func (self *Miner) Start(coinbase common.Address, threads int) {
+func (self *Miner) Start(coinbase common.Address) {
 	atomic.StoreInt32(&self.shouldStart, 1)
 	atomic.StoreInt32(&self.shouldStart, 1)
 	self.worker.setEtherbase(coinbase)
 	self.worker.setEtherbase(coinbase)
 	self.coinbase = coinbase
 	self.coinbase = coinbase
-	self.threads = threads
 
 
 	if atomic.LoadInt32(&self.canStart) == 0 {
 	if atomic.LoadInt32(&self.canStart) == 0 {
-		log.Info(fmt.Sprint("Can not start mining operation due to network sync (starts when finished)"))
+		log.Info("Network syncing, will start miner afterwards")
 		return
 		return
 	}
 	}
 	atomic.StoreInt32(&self.mining, 1)
 	atomic.StoreInt32(&self.mining, 1)
 
 
-	for i := 0; i < threads; i++ {
-		self.worker.register(NewCpuAgent(i, self.pow))
-	}
-
-	log.Info(fmt.Sprintf("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents)))
+	log.Info("Starting mining operation")
 	self.worker.start()
 	self.worker.start()
 	self.worker.commitNewWork()
 	self.worker.commitNewWork()
 }
 }
@@ -159,7 +154,9 @@ func (self *Miner) Mining() bool {
 }
 }
 
 
 func (self *Miner) HashRate() (tot int64) {
 func (self *Miner) HashRate() (tot int64) {
-	tot += int64(self.pow.Hashrate())
+	if pow, ok := self.engine.(consensus.PoW); ok {
+		tot += int64(pow.Hashrate())
+	}
 	// do we care this might race? is it worth we're rewriting some
 	// do we care this might race? is it worth we're rewriting some
 	// aspects of the worker/locking up agents so we can get an accurate
 	// aspects of the worker/locking up agents so we can get an accurate
 	// hashrate?
 	// hashrate?

+ 20 - 13
miner/remote_agent.go

@@ -18,16 +18,16 @@ package miner
 
 
 import (
 import (
 	"errors"
 	"errors"
-	"fmt"
 	"math/big"
 	"math/big"
 	"sync"
 	"sync"
 	"sync/atomic"
 	"sync/atomic"
 	"time"
 	"time"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
-	"github.com/ethereum/go-ethereum/pow"
 )
 )
 
 
 type hashrate struct {
 type hashrate struct {
@@ -42,7 +42,8 @@ type RemoteAgent struct {
 	workCh   chan *Work
 	workCh   chan *Work
 	returnCh chan<- *Result
 	returnCh chan<- *Result
 
 
-	pow         pow.PoW
+	chain       consensus.ChainReader
+	engine      consensus.Engine
 	currentWork *Work
 	currentWork *Work
 	work        map[common.Hash]*Work
 	work        map[common.Hash]*Work
 
 
@@ -52,9 +53,10 @@ type RemoteAgent struct {
 	running int32 // running indicates whether the agent is active. Call atomically
 	running int32 // running indicates whether the agent is active. Call atomically
 }
 }
 
 
-func NewRemoteAgent(pow pow.PoW) *RemoteAgent {
+func NewRemoteAgent(chain consensus.ChainReader, engine consensus.Engine) *RemoteAgent {
 	return &RemoteAgent{
 	return &RemoteAgent{
-		pow:      pow,
+		chain:    chain,
+		engine:   engine,
 		work:     make(map[common.Hash]*Work),
 		work:     make(map[common.Hash]*Work),
 		hashrate: make(map[common.Hash]hashrate),
 		hashrate: make(map[common.Hash]hashrate),
 	}
 	}
@@ -114,7 +116,7 @@ func (a *RemoteAgent) GetWork() ([3]string, error) {
 		block := a.currentWork.Block
 		block := a.currentWork.Block
 
 
 		res[0] = block.HashNoNonce().Hex()
 		res[0] = block.HashNoNonce().Hex()
-		seedHash := pow.EthashSeedHash(block.NumberU64())
+		seedHash := ethash.SeedHash(block.NumberU64())
 		res[1] = common.BytesToHash(seedHash).Hex()
 		res[1] = common.BytesToHash(seedHash).Hex()
 		// Calculate the "target" to be returned to the external miner
 		// Calculate the "target" to be returned to the external miner
 		n := big.NewInt(1)
 		n := big.NewInt(1)
@@ -129,8 +131,8 @@ func (a *RemoteAgent) GetWork() ([3]string, error) {
 	return res, errors.New("No work available yet, don't panic.")
 	return res, errors.New("No work available yet, don't panic.")
 }
 }
 
 
-// SubmitWork tries to inject a PoW solution tinto the remote agent, returning
-// whether the solution was acceted or not (not can be both a bad PoW as well as
+// SubmitWork tries to inject a pow solution into the remote agent, returning
+// whether the solution was accepted or not (not can be both a bad pow as well as
 // any other error, like no work pending).
 // any other error, like no work pending).
 func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common.Hash) bool {
 func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common.Hash) bool {
 	a.mu.Lock()
 	a.mu.Lock()
@@ -139,15 +141,20 @@ func (a *RemoteAgent) SubmitWork(nonce types.BlockNonce, mixDigest, hash common.
 	// Make sure the work submitted is present
 	// Make sure the work submitted is present
 	work := a.work[hash]
 	work := a.work[hash]
 	if work == nil {
 	if work == nil {
-		log.Info(fmt.Sprintf("Work was submitted for %x but no pending work found", hash))
+		log.Info("Work submitted but none pending", "hash", hash)
 		return false
 		return false
 	}
 	}
-	// Make sure the PoW solutions is indeed valid
-	block := work.Block.WithMiningResult(nonce, mixDigest)
-	if err := a.pow.Verify(block); err != nil {
-		log.Warn(fmt.Sprintf("Invalid PoW submitted for %x: %v", hash, err))
+	// Make sure the Engine solutions is indeed valid
+	result := work.Block.Header()
+	result.Nonce = nonce
+	result.MixDigest = mixDigest
+
+	if err := a.engine.VerifySeal(a.chain, result); err != nil {
+		log.Warn("Invalid proof-of-work submitted", "hash", hash, "err", err)
 		return false
 		return false
 	}
 	}
+	block := work.Block.WithSeal(result)
+
 	// Solutions seems to be valid, return to the miner and notify acceptance
 	// Solutions seems to be valid, return to the miner and notify acceptance
 	a.returnCh <- &Result{work, block}
 	a.returnCh <- &Result{work, block}
 	delete(a.work, hash)
 	delete(a.work, hash)

+ 4 - 5
miner/unconfirmed.go

@@ -18,7 +18,6 @@ package miner
 
 
 import (
 import (
 	"container/ring"
 	"container/ring"
-	"fmt"
 	"sync"
 	"sync"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
@@ -80,7 +79,7 @@ func (set *unconfirmedBlocks) Insert(index uint64, hash common.Hash) {
 		set.blocks.Move(-1).Link(item)
 		set.blocks.Move(-1).Link(item)
 	}
 	}
 	// Display a log for the user to notify of a new mined block unconfirmed
 	// Display a log for the user to notify of a new mined block unconfirmed
-	log.Info(fmt.Sprintf("🔨  mined potential block #%d [%x…], waiting for %d blocks to confirm", index, hash.Bytes()[:4], set.depth))
+	log.Info("🔨 mined potential block", "number", index, "hash", hash)
 }
 }
 
 
 // Shift drops all unconfirmed blocks from the set which exceed the unconfirmed sets depth
 // Shift drops all unconfirmed blocks from the set which exceed the unconfirmed sets depth
@@ -100,11 +99,11 @@ func (set *unconfirmedBlocks) Shift(height uint64) {
 		header := set.chain.GetHeaderByNumber(next.index)
 		header := set.chain.GetHeaderByNumber(next.index)
 		switch {
 		switch {
 		case header == nil:
 		case header == nil:
-			log.Warn(fmt.Sprintf("failed to retrieve header of mined block #%d [%x…]", next.index, next.hash.Bytes()[:4]))
+			log.Warn("Failed to retrieve header of mined block", "number", next.index, "hash", next.hash)
 		case header.Hash() == next.hash:
 		case header.Hash() == next.hash:
-			log.Info(fmt.Sprintf("🔗  mined block #%d [%x…] reached canonical chain", next.index, next.hash.Bytes()[:4]))
+			log.Info("🔗 block reached canonical chain", "number", next.index, "hash", next.hash)
 		default:
 		default:
-			log.Info(fmt.Sprintf("⑂ mined block #%d [%x…] became a side fork", next.index, next.hash.Bytes()[:4]))
+			log.Info("⑂ block  became a side fork", "number", next.index, "hash", next.hash)
 		}
 		}
 		// Drop the block out of the ring
 		// Drop the block out of the ring
 		if set.blocks.Value == set.blocks.Next().Value {
 		if set.blocks.Value == set.blocks.Next().Value {

+ 38 - 46
miner/worker.go

@@ -26,6 +26,8 @@ import (
 
 
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus"
+	"github.com/ethereum/go-ethereum/consensus/misc"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -34,7 +36,6 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"gopkg.in/fatih/set.v0"
 	"gopkg.in/fatih/set.v0"
 )
 )
 
 
@@ -84,6 +85,7 @@ type Result struct {
 // worker is the main object which takes care of applying messages to the new state
 // worker is the main object which takes care of applying messages to the new state
 type worker struct {
 type worker struct {
 	config *params.ChainConfig
 	config *params.ChainConfig
+	engine consensus.Engine
 
 
 	mu sync.Mutex
 	mu sync.Mutex
 
 
@@ -94,7 +96,6 @@ type worker struct {
 
 
 	agents map[Agent]struct{}
 	agents map[Agent]struct{}
 	recv   chan *Result
 	recv   chan *Result
-	pow    pow.PoW
 
 
 	eth     Backend
 	eth     Backend
 	chain   *core.BlockChain
 	chain   *core.BlockChain
@@ -123,9 +124,10 @@ type worker struct {
 	fullValidation bool
 	fullValidation bool
 }
 }
 
 
-func newWorker(config *params.ChainConfig, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
+func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
 	worker := &worker{
 	worker := &worker{
 		config:         config,
 		config:         config,
+		engine:         engine,
 		eth:            eth,
 		eth:            eth,
 		mux:            mux,
 		mux:            mux,
 		chainDb:        eth.ChainDb(),
 		chainDb:        eth.ChainDb(),
@@ -209,16 +211,10 @@ func (self *worker) stop() {
 	self.mu.Lock()
 	self.mu.Lock()
 	defer self.mu.Unlock()
 	defer self.mu.Unlock()
 	if atomic.LoadInt32(&self.mining) == 1 {
 	if atomic.LoadInt32(&self.mining) == 1 {
-		// Stop all agents.
 		for agent := range self.agents {
 		for agent := range self.agents {
 			agent.Stop()
 			agent.Stop()
-			// Remove CPU agents.
-			if _, ok := agent.(*CpuAgent); ok {
-				delete(self.agents, agent)
-			}
 		}
 		}
 	}
 	}
-
 	atomic.StoreInt32(&self.mining, 0)
 	atomic.StoreInt32(&self.mining, 0)
 	atomic.StoreInt32(&self.atWork, 0)
 	atomic.StoreInt32(&self.atWork, 0)
 }
 }
@@ -277,7 +273,7 @@ func (self *worker) wait() {
 
 
 			if self.fullValidation {
 			if self.fullValidation {
 				if _, err := self.chain.InsertChain(types.Blocks{block}); err != nil {
 				if _, err := self.chain.InsertChain(types.Blocks{block}); err != nil {
-					log.Error(fmt.Sprint("mining err", err))
+					log.Error("Mined invalid block", "err", err)
 					continue
 					continue
 				}
 				}
 				go self.mux.Post(core.NewMinedBlockEvent{Block: block})
 				go self.mux.Post(core.NewMinedBlockEvent{Block: block})
@@ -285,19 +281,16 @@ func (self *worker) wait() {
 				work.state.Commit(self.config.IsEIP158(block.Number()))
 				work.state.Commit(self.config.IsEIP158(block.Number()))
 				parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
 				parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
 				if parent == nil {
 				if parent == nil {
-					log.Error(fmt.Sprint("Invalid block found during mining"))
+					log.Error("Invalid block found during mining")
 					continue
 					continue
 				}
 				}
-
-				auxValidator := self.eth.BlockChain().AuxValidator()
-				if err := core.ValidateHeader(self.config, auxValidator, block.Header(), parent.Header(), true, false); err != nil && err != core.BlockFutureErr {
-					log.Error(fmt.Sprint("Invalid header on mined block:", err))
+				if err := self.engine.VerifyHeader(self.chain, block.Header(), false); err != nil {
+					log.Error("Invalid header on mined block", "err", err)
 					continue
 					continue
 				}
 				}
-
 				stat, err := self.chain.WriteBlock(block)
 				stat, err := self.chain.WriteBlock(block)
 				if err != nil {
 				if err != nil {
-					log.Error(fmt.Sprint("error writing block to chain", err))
+					log.Error("Failed writing block to chain", "err", err)
 					continue
 					continue
 				}
 				}
 
 
@@ -333,7 +326,7 @@ func (self *worker) wait() {
 						self.mux.Post(logs)
 						self.mux.Post(logs)
 					}
 					}
 					if err := core.WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), receipts); err != nil {
 					if err := core.WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), receipts); err != nil {
-						log.Warn(fmt.Sprint("error writing block receipts:", err))
+						log.Warn("Failed writing block receipts", "err", err)
 					}
 					}
 				}(block, work.state.Logs(), work.receipts)
 				}(block, work.state.Logs(), work.receipts)
 			}
 			}
@@ -424,9 +417,9 @@ func (self *worker) commitNewWork() {
 		tstamp = parent.Time().Int64() + 1
 		tstamp = parent.Time().Int64() + 1
 	}
 	}
 	// this will ensure we're not going off too far in the future
 	// this will ensure we're not going off too far in the future
-	if now := time.Now().Unix(); tstamp > now+4 {
+	if now := time.Now().Unix(); tstamp > now+1 {
 		wait := time.Duration(tstamp-now) * time.Second
 		wait := time.Duration(tstamp-now) * time.Second
-		log.Info(fmt.Sprint("We are too far in the future. Waiting for", wait))
+		log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait))
 		time.Sleep(wait)
 		time.Sleep(wait)
 	}
 	}
 
 
@@ -434,13 +427,19 @@ func (self *worker) commitNewWork() {
 	header := &types.Header{
 	header := &types.Header{
 		ParentHash: parent.Hash(),
 		ParentHash: parent.Hash(),
 		Number:     num.Add(num, common.Big1),
 		Number:     num.Add(num, common.Big1),
-		Difficulty: core.CalcDifficulty(self.config, uint64(tstamp), parent.Time().Uint64(), parent.Number(), parent.Difficulty()),
 		GasLimit:   core.CalcGasLimit(parent),
 		GasLimit:   core.CalcGasLimit(parent),
 		GasUsed:    new(big.Int),
 		GasUsed:    new(big.Int),
-		Coinbase:   self.coinbase,
 		Extra:      self.extra,
 		Extra:      self.extra,
 		Time:       big.NewInt(tstamp),
 		Time:       big.NewInt(tstamp),
 	}
 	}
+	// Only set the coinbase if we are mining (avoid spurious block rewards)
+	if atomic.LoadInt32(&self.mining) == 1 {
+		header.Coinbase = self.coinbase
+	}
+	if err := self.engine.Prepare(self.chain, header); err != nil {
+		log.Error("Failed to prepare header for mining", "err", err)
+		return
+	}
 	// If we are care about TheDAO hard-fork check whether to override the extra-data or not
 	// If we are care about TheDAO hard-fork check whether to override the extra-data or not
 	if daoBlock := self.config.DAOForkBlock; daoBlock != nil {
 	if daoBlock := self.config.DAOForkBlock; daoBlock != nil {
 		// Check whether the block is among the fork extra-override range
 		// Check whether the block is among the fork extra-override range
@@ -457,21 +456,19 @@ func (self *worker) commitNewWork() {
 	// Could potentially happen if starting to mine in an odd state.
 	// Could potentially happen if starting to mine in an odd state.
 	err := self.makeCurrent(parent, header)
 	err := self.makeCurrent(parent, header)
 	if err != nil {
 	if err != nil {
-		log.Info(fmt.Sprint("Could not create new env for mining, retrying on next block."))
+		log.Error("Failed to create mining context", "err", err)
 		return
 		return
 	}
 	}
 	// Create the current work task and check any fork transitions needed
 	// Create the current work task and check any fork transitions needed
 	work := self.current
 	work := self.current
 	if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 {
 	if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 {
-		core.ApplyDAOHardFork(work.state)
+		misc.ApplyDAOHardFork(work.state)
 	}
 	}
-
 	pending, err := self.eth.TxPool().Pending()
 	pending, err := self.eth.TxPool().Pending()
 	if err != nil {
 	if err != nil {
-		log.Error(fmt.Sprintf("Could not fetch pending transactions: %v", err))
+		log.Error("Failed to fetch pending transactions", "err", err)
 		return
 		return
 	}
 	}
-
 	txs := types.NewTransactionsByPriceAndNonce(pending)
 	txs := types.NewTransactionsByPriceAndNonce(pending)
 	work.commitTransactions(self.mux, txs, self.gasPrice, self.chain)
 	work.commitTransactions(self.mux, txs, self.gasPrice, self.chain)
 
 
@@ -488,31 +485,26 @@ func (self *worker) commitNewWork() {
 			break
 			break
 		}
 		}
 		if err := self.commitUncle(work, uncle.Header()); err != nil {
 		if err := self.commitUncle(work, uncle.Header()); err != nil {
-			log.Trace(fmt.Sprintf("Bad uncle found and will be removed (%x)\n", hash[:4]))
+			log.Trace("Bad uncle found and will be removed", "hash", hash)
 			log.Trace(fmt.Sprint(uncle))
 			log.Trace(fmt.Sprint(uncle))
 
 
 			badUncles = append(badUncles, hash)
 			badUncles = append(badUncles, hash)
 		} else {
 		} else {
-			log.Debug(fmt.Sprintf("committing %x as uncle\n", hash[:4]))
+			log.Debug("Committing new uncle to block", "hash", hash)
 			uncles = append(uncles, uncle.Header())
 			uncles = append(uncles, uncle.Header())
 		}
 		}
 	}
 	}
 	for _, hash := range badUncles {
 	for _, hash := range badUncles {
 		delete(self.possibleUncles, hash)
 		delete(self.possibleUncles, hash)
 	}
 	}
-
-	if atomic.LoadInt32(&self.mining) == 1 {
-		// commit state root after all state transitions.
-		core.AccumulateRewards(work.state, header, uncles)
-		header.Root = work.state.IntermediateRoot(self.config.IsEIP158(header.Number))
+	// Create the new block to seal with the consensus engine
+	if work.Block, err = self.engine.Finalize(self.chain, header, work.state, work.txs, uncles, work.receipts); err != nil {
+		log.Error("Failed to finalize block for sealing", "err", err)
+		return
 	}
 	}
-
-	// create the new block whose nonce will be mined.
-	work.Block = types.NewBlock(header, work.txs, uncles, work.receipts)
-
 	// We only care about logging if we're actually mining.
 	// We only care about logging if we're actually mining.
 	if atomic.LoadInt32(&self.mining) == 1 {
 	if atomic.LoadInt32(&self.mining) == 1 {
-		log.Info(fmt.Sprintf("commit new work on block %v with %d txs & %d uncles. Took %v\n", work.Block.Number(), work.tcount, len(uncles), time.Since(tstart)))
+		log.Info("Commit new mining work", "number", work.Block.Number(), "txs", work.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart)))
 		self.unconfirmed.Shift(work.Block.NumberU64() - 1)
 		self.unconfirmed.Shift(work.Block.NumberU64() - 1)
 	}
 	}
 	self.push(work)
 	self.push(work)
@@ -521,13 +513,13 @@ func (self *worker) commitNewWork() {
 func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
 func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
 	hash := uncle.Hash()
 	hash := uncle.Hash()
 	if work.uncles.Has(hash) {
 	if work.uncles.Has(hash) {
-		return core.UncleError("Uncle not unique")
+		return core.UncleError("uncle not unique")
 	}
 	}
 	if !work.ancestors.Has(uncle.ParentHash) {
 	if !work.ancestors.Has(uncle.ParentHash) {
-		return core.UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
+		return core.UncleError(fmt.Sprintf("uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
 	}
 	}
 	if work.family.Has(hash) {
 	if work.family.Has(hash) {
-		return core.UncleError(fmt.Sprintf("Uncle already in family (%x)", hash))
+		return core.UncleError(fmt.Sprintf("uncle already in family (%x)", hash))
 	}
 	}
 	work.uncles.Add(uncle.Hash())
 	work.uncles.Add(uncle.Hash())
 	return nil
 	return nil
@@ -552,7 +544,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
 		// Check whether the tx is replay protected. If we're not in the EIP155 hf
 		// Check whether the tx is replay protected. If we're not in the EIP155 hf
 		// phase, start ignoring the sender until we do.
 		// phase, start ignoring the sender until we do.
 		if tx.Protected() && !env.config.IsEIP155(env.header.Number) {
 		if tx.Protected() && !env.config.IsEIP155(env.header.Number) {
-			log.Trace(fmt.Sprintf("Transaction (%x) is replay protected, but we haven't yet hardforked. Transaction will be ignored until we hardfork.\n", tx.Hash()))
+			log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", env.config.EIP155Block)
 
 
 			txs.Pop()
 			txs.Pop()
 			continue
 			continue
@@ -561,7 +553,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
 		// Ignore any transactions (and accounts subsequently) with low gas limits
 		// Ignore any transactions (and accounts subsequently) with low gas limits
 		if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
 		if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
 			// Pop the current low-priced transaction without shifting in the next from the account
 			// Pop the current low-priced transaction without shifting in the next from the account
-			log.Info(fmt.Sprintf("Transaction (%x) below gas price (tx=%dwei ask=%dwei). All sequential txs from this address(%x) will be ignored\n", tx.Hash().Bytes()[:4], tx.GasPrice(), gasPrice, from[:4]))
+			log.Warn("Transaction below gas price", "sender", from, "hash", tx.Hash(), "have", tx.GasPrice(), "want", gasPrice)
 
 
 			env.lowGasTxs = append(env.lowGasTxs, tx)
 			env.lowGasTxs = append(env.lowGasTxs, tx)
 			txs.Pop()
 			txs.Pop()
@@ -575,12 +567,12 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
 		switch {
 		switch {
 		case core.IsGasLimitErr(err):
 		case core.IsGasLimitErr(err):
 			// Pop the current out-of-gas transaction without shifting in the next from the account
 			// Pop the current out-of-gas transaction without shifting in the next from the account
-			log.Trace(fmt.Sprintf("Gas limit reached for (%x) in this block. Continue to try smaller txs\n", from[:4]))
+			log.Trace("Gas limit exceeded for current block", "sender", from)
 			txs.Pop()
 			txs.Pop()
 
 
 		case err != nil:
 		case err != nil:
 			// Pop the current failed transaction without shifting in the next from the account
 			// Pop the current failed transaction without shifting in the next from the account
-			log.Trace(fmt.Sprintf("Transaction (%x) failed, will be removed: %v\n", tx.Hash().Bytes()[:4], err))
+			log.Trace("Transaction failed, will be removed", "hash", tx.Hash(), "err", err)
 			env.failedTxs = append(env.failedTxs, tx)
 			env.failedTxs = append(env.failedTxs, tx)
 			txs.Pop()
 			txs.Pop()
 
 

+ 2 - 2
params/util.go

@@ -38,6 +38,6 @@ var (
 	TestNetSpuriousDragon = big.NewInt(10)
 	TestNetSpuriousDragon = big.NewInt(10)
 	MainNetSpuriousDragon = big.NewInt(2675000)
 	MainNetSpuriousDragon = big.NewInt(2675000)
 
 
-	TestNetChainID = big.NewInt(3) // Test net default chain ID
-	MainNetChainID = big.NewInt(1) // main net default chain ID
+	TestNetChainID = big.NewInt(3) // Testnet default chain ID
+	MainNetChainID = big.NewInt(1) // Mainnet default chain ID
 )
 )

+ 0 - 58
pow/pow.go

@@ -1,58 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package pow
-
-import (
-	"math/big"
-
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core/types"
-)
-
-type Block interface {
-	Difficulty() *big.Int
-	HashNoNonce() common.Hash
-	Nonce() uint64
-	MixDigest() common.Hash
-	NumberU64() uint64
-}
-
-type ChainManager interface {
-	GetBlockByNumber(uint64) *types.Block
-	CurrentBlock() *types.Block
-}
-
-type PoW interface {
-	Verify(block Block) error
-	Search(block Block, stop <-chan struct{}) (uint64, []byte)
-	Hashrate() float64
-}
-
-// FakePow is a non-validating proof of work implementation.
-// It returns true from Verify for any block.
-type FakePow struct{}
-
-// Verify implements PoW, returning a success for an input.
-func (pow FakePow) Verify(block Block) error { return nil }
-
-// Search implements PoW, returning the nonce 0 for any call.
-func (pow FakePow) Search(block Block, stop <-chan struct{}) (uint64, []byte) {
-	return 0, nil
-}
-
-// Hashrate implements PoW, returning 0.
-func (pow FakePow) Hashrate() float64 { return 0 }

+ 2 - 2
tests/block_test_util.go

@@ -27,6 +27,7 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/types"
@@ -35,7 +36,6 @@ import (
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
 	"github.com/ethereum/go-ethereum/rlp"
 )
 )
 
 
@@ -172,7 +172,7 @@ func runBlockTest(homesteadBlock, daoForkBlock, gasPriceFork *big.Int, test *Blo
 	core.WriteHeadBlockHash(db, test.Genesis.Hash())
 	core.WriteHeadBlockHash(db, test.Genesis.Hash())
 	evmux := new(event.TypeMux)
 	evmux := new(event.TypeMux)
 	config := &params.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, EIP150Block: gasPriceFork}
 	config := &params.ChainConfig{HomesteadBlock: homesteadBlock, DAOForkBlock: daoForkBlock, DAOForkSupport: true, EIP150Block: gasPriceFork}
-	chain, err := core.NewBlockChain(db, config, pow.NewSharedEthash(), evmux, vm.Config{})
+	chain, err := core.NewBlockChain(db, config, ethash.NewShared(), evmux, vm.Config{})
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}

+ 1 - 0
trie/iterator.go

@@ -18,6 +18,7 @@ package trie
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common"
 )
 )