Skip to content

Commit 0977795

Browse files
karalabefjl
authored andcommitted
core, consensus: pluggable consensus engines (ethereum#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.
1 parent e50a5b7 commit 0977795

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1682
-1427
lines changed

accounts/abi/bind/backends/simulated.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ import (
2727
"github.com/ethereum/go-ethereum/accounts/abi/bind"
2828
"github.com/ethereum/go-ethereum/common"
2929
"github.com/ethereum/go-ethereum/common/math"
30+
"github.com/ethereum/go-ethereum/consensus/ethash"
3031
"github.com/ethereum/go-ethereum/core"
3132
"github.com/ethereum/go-ethereum/core/state"
3233
"github.com/ethereum/go-ethereum/core/types"
3334
"github.com/ethereum/go-ethereum/core/vm"
3435
"github.com/ethereum/go-ethereum/ethdb"
3536
"github.com/ethereum/go-ethereum/event"
3637
"github.com/ethereum/go-ethereum/params"
37-
"github.com/ethereum/go-ethereum/pow"
3838
)
3939

4040
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
@@ -61,7 +61,7 @@ func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
6161
database, _ := ethdb.NewMemDatabase()
6262
genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
6363
genesis.MustCommit(database)
64-
blockchain, _ := core.NewBlockChain(database, genesis.Config, new(pow.FakePow), new(event.TypeMux), vm.Config{})
64+
blockchain, _ := core.NewBlockChain(database, genesis.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{})
6565
backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config}
6666
backend.rollback()
6767
return backend

cmd/evm/disasm.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ import (
2020
"errors"
2121
"fmt"
2222
"io/ioutil"
23+
"strings"
2324

2425
"github.com/ethereum/go-ethereum/core/asm"
2526
cli "gopkg.in/urfave/cli.v1"
26-
"strings"
2727
)
2828

2929
var disasmCommand = cli.Command{

cmd/geth/main.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,15 @@ func startNode(ctx *cli.Context, stack *node.Node) {
303303
if err := stack.Service(&ethereum); err != nil {
304304
utils.Fatalf("ethereum service not running: %v", err)
305305
}
306-
if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil {
306+
if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
307+
type threaded interface {
308+
SetThreads(threads int)
309+
}
310+
if th, ok := ethereum.Engine().(threaded); ok {
311+
th.SetThreads(threads)
312+
}
313+
}
314+
if err := ethereum.StartMining(); err != nil {
307315
utils.Fatalf("Failed to start mining: %v", err)
308316
}
309317
}

cmd/geth/misccmd.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ import (
2626
"strings"
2727

2828
"github.com/ethereum/go-ethereum/cmd/utils"
29+
"github.com/ethereum/go-ethereum/consensus/ethash"
2930
"github.com/ethereum/go-ethereum/eth"
3031
"github.com/ethereum/go-ethereum/params"
31-
"github.com/ethereum/go-ethereum/pow"
3232
"gopkg.in/urfave/cli.v1"
3333
)
3434

@@ -87,7 +87,7 @@ func makedag(ctx *cli.Context) error {
8787
utils.Fatalf("Can't find dir")
8888
}
8989
fmt.Println("making DAG, this could take awhile...")
90-
pow.MakeDataset(blockNum, dir)
90+
ethash.MakeDataset(blockNum, dir)
9191
}
9292
default:
9393
wrongArgs()

cmd/utils/flags.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/ethereum/go-ethereum/accounts"
3333
"github.com/ethereum/go-ethereum/accounts/keystore"
3434
"github.com/ethereum/go-ethereum/common"
35+
"github.com/ethereum/go-ethereum/consensus/ethash"
3536
"github.com/ethereum/go-ethereum/core"
3637
"github.com/ethereum/go-ethereum/core/state"
3738
"github.com/ethereum/go-ethereum/core/vm"
@@ -49,7 +50,6 @@ import (
4950
"github.com/ethereum/go-ethereum/p2p/nat"
5051
"github.com/ethereum/go-ethereum/p2p/netutil"
5152
"github.com/ethereum/go-ethereum/params"
52-
"github.com/ethereum/go-ethereum/pow"
5353
"github.com/ethereum/go-ethereum/rpc"
5454
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
5555
"gopkg.in/urfave/cli.v1"
@@ -149,7 +149,7 @@ var (
149149
}
150150
TestNetFlag = cli.BoolFlag{
151151
Name: "testnet",
152-
Usage: "Ropsten network: pre-configured test network",
152+
Usage: "Ropsten network: pre-configured proof-of-work test network",
153153
}
154154
DevModeFlag = cli.BoolFlag{
155155
Name: "dev",
@@ -921,16 +921,16 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
921921
var err error
922922
chainDb = MakeChainDatabase(ctx, stack)
923923

924-
seal := pow.PoW(pow.FakePow{})
924+
engine := ethash.NewFaker()
925925
if !ctx.GlobalBool(FakePoWFlag.Name) {
926-
seal = pow.NewFullEthash("", 1, 0, "", 1, 0)
926+
engine = ethash.New("", 1, 0, "", 1, 0)
927927
}
928928
config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
929929
if err != nil {
930930
Fatalf("%v", err)
931931
}
932932
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
933-
chain, err = core.NewBlockChain(chainDb, config, seal, new(event.TypeMux), vmcfg)
933+
chain, err = core.NewBlockChain(chainDb, config, engine, new(event.TypeMux), vmcfg)
934934
if err != nil {
935935
Fatalf("Can't create BlockChain: %v", err)
936936
}

consensus/consensus.go

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright 2017 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
// Package consensus implements different Ethereum consensus engines.
18+
package consensus
19+
20+
import (
21+
"github.com/ethereum/go-ethereum/common"
22+
"github.com/ethereum/go-ethereum/core/state"
23+
"github.com/ethereum/go-ethereum/core/types"
24+
"github.com/ethereum/go-ethereum/params"
25+
"github.com/ethereum/go-ethereum/rpc"
26+
)
27+
28+
// ChainReader defines a small collection of methods needed to access the local
29+
// blockchain during header and/or uncle verification.
30+
type ChainReader interface {
31+
// Config retrieves the blockchain's chain configuration.
32+
Config() *params.ChainConfig
33+
34+
// CurrentHeader retrieves the current header from the local chain.
35+
CurrentHeader() *types.Header
36+
37+
// GetHeader retrieves a block header from the database by hash and number.
38+
GetHeader(hash common.Hash, number uint64) *types.Header
39+
40+
// GetHeaderByNumber retrieves a block header from the database by number.
41+
GetHeaderByNumber(number uint64) *types.Header
42+
43+
// GetBlock retrieves a block from the database by hash and number.
44+
GetBlock(hash common.Hash, number uint64) *types.Block
45+
}
46+
47+
// Engine is an algorithm agnostic consensus engine.
48+
type Engine interface {
49+
// VerifyHeader checks whether a header conforms to the consensus rules of a
50+
// given engine. Verifying the seal may be done optionally here, or explicitly
51+
// via the VerifySeal method.
52+
VerifyHeader(chain ChainReader, header *types.Header, seal bool) error
53+
54+
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
55+
// concurrently. The method returns a quit channel to abort the operations and
56+
// a results channel to retrieve the async verifications (the order is that of
57+
// the input slice).
58+
VerifyHeaders(chain ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error)
59+
60+
// VerifyUncles verifies that the given block's uncles conform to the consensus
61+
// rules of a given engine.
62+
VerifyUncles(chain ChainReader, block *types.Block) error
63+
64+
// VerifySeal checks whether the crypto seal on a header is valid according to
65+
// the consensus rules of the given engine.
66+
VerifySeal(chain ChainReader, header *types.Header) error
67+
68+
// Prepare initializes the consensus fields of a block header according to the
69+
// rules of a particular engine. The changes are executed inline.
70+
Prepare(chain ChainReader, header *types.Header) error
71+
72+
// Finalize runs any post-transaction state modifications (e.g. block rewards)
73+
// and assembles the final block.
74+
//
75+
// Note, the block header and state database might be updated to reflect any
76+
// consensus rules that happen at finalization (e.g. block rewards).
77+
Finalize(chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
78+
uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error)
79+
80+
// Seal generates a new block for the given input block with the local miner's
81+
// seal place on top.
82+
Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error)
83+
84+
// APIs returns the RPC APIs this consensus engine provides.
85+
APIs(chain ChainReader) []rpc.API
86+
}
87+
88+
// PoW is a consensus engine based on proof-of-work.
89+
type PoW interface {
90+
Engine
91+
92+
// Hashrate returns the current mining hashrate of a PoW consensus engine.
93+
Hashrate() float64
94+
}

pow/ethash_algo.go renamed to consensus/ethash/algorithm.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// You should have received a copy of the GNU Lesser General Public License
1515
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
1616

17-
package pow
17+
package ethash
1818

1919
import (
2020
"encoding/binary"

pow/ethash_algo_go1.7.go renamed to consensus/ethash/algorithm_go1.7.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
// +build !go1.8
1818

19-
package pow
19+
package ethash
2020

2121
// cacheSize calculates and returns the size of the ethash verification cache that
2222
// belongs to a certain block number. The cache size grows linearly, however, we

pow/ethash_algo_go1.8.go renamed to consensus/ethash/algorithm_go1.8.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
// +build go1.8
1818

19-
package pow
19+
package ethash
2020

2121
import "math/big"
2222

pow/ethash_algo_go1.8_test.go renamed to consensus/ethash/algorithm_go1.8_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
// +build go1.8
1818

19-
package pow
19+
package ethash
2020

2121
import "testing"
2222

pow/ethash_algo_test.go renamed to consensus/ethash/algorithm_test.go

+3-14
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// You should have received a copy of the GNU Lesser General Public License
1515
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
1616

17-
package pow
17+
package ethash
1818

1919
import (
2020
"bytes"
@@ -704,26 +704,15 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) {
704704
go func(idx int) {
705705
defer pend.Done()
706706

707-
ethash := NewFullEthash(cachedir, 0, 1, "", 0, 0)
708-
if err := ethash.Verify(block); err != nil {
707+
ethash := New(cachedir, 0, 1, "", 0, 0)
708+
if err := ethash.VerifySeal(nil, block.Header()); err != nil {
709709
t.Errorf("proc %d: block verification failed: %v", idx, err)
710710
}
711711
}(i)
712712
}
713713
pend.Wait()
714714
}
715715

716-
func TestTestMode(t *testing.T) {
717-
head := &types.Header{Difficulty: big.NewInt(100)}
718-
ethash := NewTestEthash()
719-
nonce, mix := ethash.Search(types.NewBlockWithHeader(head), nil)
720-
head.Nonce = types.EncodeNonce(nonce)
721-
copy(head.MixDigest[:], mix)
722-
if err := ethash.Verify(types.NewBlockWithHeader(head)); err != nil {
723-
t.Error("unexpected Verify error:", err)
724-
}
725-
}
726-
727716
// Benchmarks the cache generation performance.
728717
func BenchmarkCacheGeneration(b *testing.B) {
729718
for i := 0; i < b.N; i++ {

0 commit comments

Comments
 (0)