Skip to content

Commit

Permalink
core, consensus: pluggable consensus engines (ethereum#3817)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
karalabe authored and fjl committed Apr 4, 2017
1 parent e50a5b7 commit 0977795
Show file tree
Hide file tree
Showing 61 changed files with 1,682 additions and 1,427 deletions.
4 changes: 2 additions & 2 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"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/state"
"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/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
)

// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
Expand All @@ -61,7 +61,7 @@ func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
database, _ := ethdb.NewMemDatabase()
genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
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.rollback()
return backend
Expand Down
2 changes: 1 addition & 1 deletion cmd/evm/disasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import (
"errors"
"fmt"
"io/ioutil"
"strings"

"github.com/ethereum/go-ethereum/core/asm"
cli "gopkg.in/urfave/cli.v1"
"strings"
)

var disasmCommand = cli.Command{
Expand Down
10 changes: 9 additions & 1 deletion cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,15 @@ func startNode(ctx *cli.Context, stack *node.Node) {
if err := stack.Service(&ethereum); err != nil {
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)
}
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/geth/misccmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ import (
"strings"

"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/params"
"github.com/ethereum/go-ethereum/pow"
"gopkg.in/urfave/cli.v1"
)

Expand Down Expand Up @@ -87,7 +87,7 @@ func makedag(ctx *cli.Context) error {
utils.Fatalf("Can't find dir")
}
fmt.Println("making DAG, this could take awhile...")
pow.MakeDataset(blockNum, dir)
ethash.MakeDataset(blockNum, dir)
}
default:
wrongArgs()
Expand Down
10 changes: 5 additions & 5 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"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/state"
"github.com/ethereum/go-ethereum/core/vm"
Expand All @@ -49,7 +50,6 @@ import (
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/rpc"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
"gopkg.in/urfave/cli.v1"
Expand Down Expand Up @@ -149,7 +149,7 @@ var (
}
TestNetFlag = cli.BoolFlag{
Name: "testnet",
Usage: "Ropsten network: pre-configured test network",
Usage: "Ropsten network: pre-configured proof-of-work test network",
}
DevModeFlag = cli.BoolFlag{
Name: "dev",
Expand Down Expand Up @@ -921,16 +921,16 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
var err error
chainDb = MakeChainDatabase(ctx, stack)

seal := pow.PoW(pow.FakePow{})
engine := ethash.NewFaker()
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))
if err != nil {
Fatalf("%v", err)
}
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 {
Fatalf("Can't create BlockChain: %v", err)
}
Expand Down
94 changes: 94 additions & 0 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 1 addition & 1 deletion pow/ethash_algo.go → consensus/ethash/algorithm.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// 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
package ethash

import (
"encoding/binary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

// +build !go1.8

package pow
package ethash

// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

// +build go1.8

package pow
package ethash

import "math/big"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

// +build go1.8

package pow
package ethash

import "testing"

Expand Down
17 changes: 3 additions & 14 deletions pow/ethash_algo_test.go → consensus/ethash/algorithm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// 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
package ethash

import (
"bytes"
Expand Down Expand Up @@ -704,26 +704,15 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) {
go func(idx int) {
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)
}
}(i)
}
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.
func BenchmarkCacheGeneration(b *testing.B) {
for i := 0; i < b.N; i++ {
Expand Down
Loading

0 comments on commit 0977795

Please sign in to comment.