Skip to content

Commit

Permalink
Merge istanbul into (celo) master (ethereum#135)
Browse files Browse the repository at this point in the history
* cmd, consensus, eth, ethstats: add protocol interface into consensus to support custom messages

* params: add Istanbul consensus engine config to ChainConfig

* cmd/*: add Istanbul command line flags

* consensus/istanbul, eth: add Istanbul configuration

* node: add an interface to retrieve node key from config

* core/types: add Istanbul specific block hash calculation

* internal/web3ext: add Istanbul JS RPC API

* consensus: add Istanbul consensus engine interface

* consensus/istanbul: Istanbul core implementation

* consensus/istanbul: add tests for Istanbul core

* consensus/istanbul: common Istanbul interfaces and types

* consensus/istanbul: Istanbul validator set implementation

* consensus/istanbul: Istanbul consensus backend implementation

* core, les, eth, miner: Istanbul consensus integration

* cmd/*, core, params: add ottoman testnet

* Address comments

* Fix Istanbul lint (ethereum#137)

* Remove unused vars for lint

* Remove unnecessary conversion

* Don't propose empty blocks with Istanbul (ethereum#134)

* Make istanbul.Backend a public type

* Don't mine empty block with Istanbul engine unless necessary

* PR comments

* Revert to original order

* Add test fixes

* PR comments

* Update the expected hash given that celo headers have a different payload with BlockSignature

* Make Istanbul's Seal asynchronous

Originally, when Istanbul was written, the Seal method was synchronous,
i.e. it would return when the sealing process was done (or cancelled).
Now that is no longer the case, in fact the miner expects the Seal to
return to be able to respond/intiate other Seal's. This commit allows
Istanbul to do so.

* Notify the Istanbul engine of new ChainHeads

During the merge, we removed this crucial line, where the worker will
notify the Istanbul engine of new chain heads that crucially allow its
peers to increse the sequence number for the next Seal.

* Apply celolatest syncmode mods to Istanbul

* [Istanbul] Seal/NewHeadChain fixes (ethereum#147)

* Make Istanbul's Seal asynchronous

Originally, when Istanbul was written, the Seal method was synchronous,
i.e. it would return when the sealing process was done (or cancelled).
Now that is no longer the case, in fact the miner expects the Seal to
return to be able to respond/intiate other Seal's. This commit allows
Istanbul to do so.

* Notify the Istanbul engine of new ChainHeads

During the merge, we removed this crucial line, where the worker will
notify the Istanbul engine of new chain heads that crucially allow its
peers to increse the sequence number for the next Seal.

* Fix test

* Fix test
  • Loading branch information
nambrot authored Mar 26, 2019
1 parent ec059a8 commit e75fd17
Show file tree
Hide file tree
Showing 76 changed files with 9,020 additions and 58 deletions.
3 changes: 3 additions & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ var (
utils.TestnetFlag,
utils.RinkebyFlag,
utils.GoerliFlag,
utils.OttomanFlag,
utils.VMEnableDebugFlag,
utils.NetworkIdFlag,
utils.ConstantinopleOverrideFlag,
Expand All @@ -139,6 +140,8 @@ var (
utils.EWASMInterpreterFlag,
utils.EVMInterpreterFlag,
configFileFlag,
utils.IstanbulRequestTimeoutFlag,
utils.IstanbulBlockPeriodFlag,
}

rpcFlags = []cli.Flag{
Expand Down
1 change: 0 additions & 1 deletion cmd/geth/misccmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ func version(ctx *cli.Context) error {
fmt.Println("Git Commit:", gitCommit)
}
fmt.Println("Architecture:", runtime.GOARCH)
fmt.Println("Protocol Versions:", eth.ProtocolVersions)
fmt.Println("Network Id:", eth.DefaultConfig.NetworkId)
fmt.Println("Go Version:", runtime.Version())
fmt.Println("Operating System:", runtime.GOOS)
Expand Down
8 changes: 8 additions & 0 deletions cmd/geth/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.TestnetFlag,
utils.RinkebyFlag,
utils.GoerliFlag,
utils.OttomanFlag,
utils.SyncModeFlag,
utils.GCModeFlag,
utils.EthStatsURLFlag,
Expand Down Expand Up @@ -252,6 +253,13 @@ var AppHelpFlagGroups = []flagGroup{
{
Name: "MISC",
},
{
Name: "ISTANBUL",
Flags: []cli.Flag{
utils.IstanbulRequestTimeoutFlag,
utils.IstanbulBlockPeriodFlag,
},
},
}

// byCategory sorts an array of flagGroup by Name in the order
Expand Down
46 changes: 43 additions & 3 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ var (
}
NetworkIdFlag = cli.Uint64Flag{
Name: "networkid",
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby, 5=Ottoman)",
Value: eth.DefaultConfig.NetworkId,
}
TestnetFlag = cli.BoolFlag{
Expand All @@ -153,6 +153,10 @@ var (
Name: "dev",
Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
}
OttomanFlag = cli.BoolFlag{
Name: "ottoman",
Usage: "Ottoman network: pre-configured istanbul bft test network",
}
DeveloperPeriodFlag = cli.IntFlag{
Name: "dev.period",
Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
Expand Down Expand Up @@ -655,6 +659,18 @@ var (
Usage: "External EVM configuration (default = built-in interpreter)",
Value: "",
}

// Istanbul settings
IstanbulRequestTimeoutFlag = cli.Uint64Flag{
Name: "istanbul.requesttimeout",
Usage: "Timeout for each Istanbul round in milliseconds",
Value: eth.DefaultConfig.Istanbul.RequestTimeout,
}
IstanbulBlockPeriodFlag = cli.Uint64Flag{
Name: "istanbul.blockperiod",
Usage: "Default minimum difference between two consecutive block's timestamps in seconds",
Value: eth.DefaultConfig.Istanbul.BlockPeriod,
}
)

// MakeDataDir retrieves the currently requested data directory, terminating
Expand All @@ -671,6 +687,9 @@ func MakeDataDir(ctx *cli.Context) string {
if ctx.GlobalBool(GoerliFlag.Name) {
return filepath.Join(path, "goerli")
}
if ctx.GlobalBool(OttomanFlag.Name) {
return filepath.Join(path, "ottoman")
}
return path
}
Fatalf("Cannot determine default data directory, please set manually (--datadir)")
Expand Down Expand Up @@ -727,6 +746,8 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
urls = params.RinkebyBootnodes
case ctx.GlobalBool(GoerliFlag.Name):
urls = params.GoerliBootnodes
case ctx.GlobalBool(OttomanFlag.Name):
urls = params.OttomanBootnodes
case cfg.BootstrapNodes != nil:
return // already set, don't apply defaults.
}
Expand Down Expand Up @@ -1052,6 +1073,8 @@ func setDataDir(ctx *cli.Context, cfg *node.Config) {
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
case ctx.GlobalBool(GoerliFlag.Name):
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
case ctx.GlobalBool(OttomanFlag.Name):
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ottoman")
}
}

Expand Down Expand Up @@ -1173,7 +1196,16 @@ func setWhitelist(ctx *cli.Context, cfg *eth.Config) {
}
}

// checkExclusive verifies that only a single instance of the provided flags was
func setIstanbul(ctx *cli.Context, cfg *eth.Config) {
if ctx.GlobalIsSet(IstanbulRequestTimeoutFlag.Name) {
cfg.Istanbul.RequestTimeout = ctx.GlobalUint64(IstanbulRequestTimeoutFlag.Name)
}
if ctx.GlobalIsSet(IstanbulBlockPeriodFlag.Name) {
cfg.Istanbul.BlockPeriod = ctx.GlobalUint64(IstanbulBlockPeriodFlag.Name)
}
}

// checkExclusive verifies that only a single isntance of the provided flags was
// set by the user. Each flag might optionally be followed by a string type to
// specialize it further.
func checkExclusive(ctx *cli.Context, args ...interface{}) {
Expand Down Expand Up @@ -1230,7 +1262,7 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
// SetEthConfig applies eth-related command line flags to the config.
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
// Avoid conflicting network flags
checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag, GoerliFlag)
checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag, GoerliFlag, OttomanFlag)
checkExclusive(ctx, LightServFlag, SyncModeFlag, "light")

ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
Expand All @@ -1240,6 +1272,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
setTxPool(ctx, &cfg.TxPool)
setEthash(ctx, cfg)
setWhitelist(ctx, cfg)
setIstanbul(ctx, cfg)

if ctx.GlobalIsSet(SyncModeFlag.Name) {
cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
Expand Down Expand Up @@ -1361,6 +1394,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
cfg.MinerGasPrice = big.NewInt(1)
}
case ctx.GlobalBool(OttomanFlag.Name):
if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 5
}
cfg.Genesis = core.DefaultOttomanGenesisBlock()
}
// TODO(fjl): move trie cache generations into config
if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 {
Expand Down Expand Up @@ -1498,6 +1536,8 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
genesis = core.DefaultGoerliGenesisBlock()
case ctx.GlobalBool(DeveloperFlag.Name):
Fatalf("Developer chains are ephemeral")
case ctx.GlobalBool(OttomanFlag.Name):
genesis = core.DefaultOttomanGenesisBlock()
}
return genesis
}
Expand Down
5 changes: 5 additions & 0 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -752,3 +752,8 @@ func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API {
Public: false,
}}
}

// Protocol implements consensus.Engine.Protocol
func (c *Clique) Protocol() consensus.Protocol {
return consensus.EthProtocol
}
26 changes: 26 additions & 0 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ 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/p2p"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
Expand Down Expand Up @@ -105,6 +106,20 @@ type Engine interface {

// Close terminates any background threads maintained by the consensus engine.
Close() error
// Protocol returns the protocol for this consensus
Protocol() Protocol
}

// Handler should be implemented if the consensus needs to handle and send peer messages
type Handler interface {
// NewChainHead handles a new head block
NewChainHead() error

// HandleMsg handles a message from peer
HandleMsg(address common.Address, data p2p.Msg) (bool, error)

// SetBroadcaster sets the broadcaster to send message to peers
SetBroadcaster(Broadcaster)
}

// PoW is a consensus engine based on proof-of-work.
Expand All @@ -114,3 +129,14 @@ type PoW interface {
// Hashrate returns the current mining hashrate of a PoW consensus engine.
Hashrate() float64
}

// Istanbul is a consensus engine to avoid byzantine failure
type Istanbul interface {
Engine

// Start starts the engine
Start(chain ChainReader, currentBlock func() *types.Block, hasBadBlock func(hash common.Hash) bool) error

// Stop stops the engine
Stop() error
}
5 changes: 5 additions & 0 deletions consensus/ethash/ethash.go
Original file line number Diff line number Diff line change
Expand Up @@ -715,3 +715,8 @@ func (ethash *Ethash) APIs(chain consensus.ChainReader) []rpc.API {
func SeedHash(block uint64) []byte {
return seedHash(block)
}

// Protocol implements consensus.Engine.Protocol
func (ethash *Ethash) Protocol() consensus.Protocol {
return consensus.EthProtocol
}
73 changes: 73 additions & 0 deletions consensus/istanbul/backend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// 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 istanbul

import (
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
)

// Backend provides application specific functions for Istanbul core
type Backend interface {
// Address returns the owner's address
Address() common.Address

// Validators returns the validator set
Validators(proposal Proposal) ValidatorSet

// EventMux returns the event mux in backend
EventMux() *event.TypeMux

// Broadcast sends a message to all validators (include self)
Broadcast(valSet ValidatorSet, payload []byte) error

// Gossip sends a message to all validators (exclude self)
Gossip(valSet ValidatorSet, payload []byte) error

// Commit delivers an approved proposal to backend.
// The delivered proposal will be put into blockchain.
Commit(proposal Proposal, seals [][]byte) error

// Verify verifies the proposal. If a consensus.ErrFutureBlock error is returned,
// the time difference of the proposal and current time is also returned.
Verify(Proposal) (time.Duration, error)

// Sign signs input data with the backend's private key
Sign([]byte) ([]byte, error)

// CheckSignature verifies the signature by checking if it's signed by
// the given validator
CheckSignature(data []byte, addr common.Address, sig []byte) error

// LastProposal retrieves latest committed proposal and the address of proposer
LastProposal() (Proposal, common.Address)

// HasProposal checks if the combination of the given hash and height matches any existing blocks
HasProposal(hash common.Hash, number *big.Int) bool

// GetProposer returns the proposer of the given block height
GetProposer(number uint64) common.Address

// ParentValidators returns the validator set of the given proposal's parent block
ParentValidators(proposal Proposal) ValidatorSet

// HasBadProposal returns whether the block with the hash is a bad block
HasBadProposal(hash common.Hash) bool
}
Loading

0 comments on commit e75fd17

Please sign in to comment.