forked from cerc-io/plugeth
cmd, eth: support switching client modes of operation
This commit is contained in:
parent
10ed107ba2
commit
92f9a3e5fa
@ -304,6 +304,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
|
||||
utils.DataDirFlag,
|
||||
utils.BlockchainVersionFlag,
|
||||
utils.OlympicFlag,
|
||||
utils.EthModeFlag,
|
||||
utils.EthVersionFlag,
|
||||
utils.CacheFlag,
|
||||
utils.JSpathFlag,
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/ethereum/ethash"
|
||||
@ -148,9 +149,14 @@ var (
|
||||
Name: "olympic",
|
||||
Usage: "Use olympic style protocol",
|
||||
}
|
||||
EthModeFlag = cli.StringFlag{
|
||||
Name: "mode",
|
||||
Value: "archive",
|
||||
Usage: "Client mode of operation (archive, full, light)",
|
||||
}
|
||||
EthVersionFlag = cli.IntFlag{
|
||||
Name: "eth",
|
||||
Value: 62,
|
||||
Value: 63,
|
||||
Usage: "Highest eth protocol to advertise (temporary, dev option)",
|
||||
}
|
||||
|
||||
@ -425,12 +431,25 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
||||
if err != nil {
|
||||
glog.V(logger.Error).Infoln("WARNING: No etherbase set and no accounts found as default")
|
||||
}
|
||||
|
||||
// Resolve the mode of opeation from the string flag
|
||||
var clientMode eth.Mode
|
||||
switch strings.ToLower(ctx.GlobalString(EthModeFlag.Name)) {
|
||||
case "archive":
|
||||
clientMode = eth.ArchiveMode
|
||||
case "full":
|
||||
clientMode = eth.FullMode
|
||||
case "light":
|
||||
clientMode = eth.LightMode
|
||||
default:
|
||||
glog.Fatalf("Unknown node type requested: %s", ctx.GlobalString(EthModeFlag.Name))
|
||||
}
|
||||
// Assemble the entire eth configuration and return
|
||||
cfg := ð.Config{
|
||||
Name: common.MakeName(clientID, version),
|
||||
DataDir: MustDataDir(ctx),
|
||||
GenesisNonce: ctx.GlobalInt(GenesisNonceFlag.Name),
|
||||
GenesisFile: ctx.GlobalString(GenesisFileFlag.Name),
|
||||
Mode: clientMode,
|
||||
BlockChainVersion: ctx.GlobalInt(BlockchainVersionFlag.Name),
|
||||
DatabaseCache: ctx.GlobalInt(CacheFlag.Name),
|
||||
SkipBcVersionCheck: false,
|
||||
@ -499,7 +518,6 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
|
||||
|
||||
glog.V(logger.Info).Infoln("dev mode enabled")
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ type Config struct {
|
||||
GenesisFile string
|
||||
GenesisBlock *types.Block // used by block tests
|
||||
Olympic bool
|
||||
Mode Mode
|
||||
|
||||
BlockChainVersion int
|
||||
SkipBcVersionCheck bool // e.g. blockchain export
|
||||
@ -398,8 +399,9 @@ func New(config *Config) (*Ethereum, error) {
|
||||
|
||||
eth.blockProcessor = core.NewBlockProcessor(chainDb, eth.pow, eth.blockchain, eth.EventMux())
|
||||
eth.blockchain.SetProcessor(eth.blockProcessor)
|
||||
eth.protocolManager = NewProtocolManager(config.NetworkId, eth.eventMux, eth.txPool, eth.pow, eth.blockchain, chainDb)
|
||||
|
||||
if eth.protocolManager, err = NewProtocolManager(config.Mode, config.NetworkId, eth.eventMux, eth.txPool, eth.pow, eth.blockchain, chainDb); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eth.miner = miner.New(eth, eth.EventMux(), eth.pow)
|
||||
eth.miner.SetGasPrice(config.GasPrice)
|
||||
eth.miner.SetExtra(config.ExtraData)
|
||||
|
@ -17,6 +17,7 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
@ -42,6 +43,10 @@ const (
|
||||
estHeaderRlpSize = 500 // Approximate size of an RLP encoded block header
|
||||
)
|
||||
|
||||
// errIncompatibleConfig is returned if the requested protocols and configs are
|
||||
// not compatible (low protocol version restrictions and high requirements).
|
||||
var errIncompatibleConfig = errors.New("incompatible configuration")
|
||||
|
||||
func errResp(code errCode, format string, v ...interface{}) error {
|
||||
return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
|
||||
}
|
||||
@ -49,17 +54,8 @@ func errResp(code errCode, format string, v ...interface{}) error {
|
||||
type hashFetcherFn func(common.Hash) error
|
||||
type blockFetcherFn func([]common.Hash) error
|
||||
|
||||
// extProt is an interface which is passed around so we can expose GetHashes and GetBlock without exposing it to the rest of the protocol
|
||||
// extProt is passed around to peers which require to GetHashes and GetBlocks
|
||||
type extProt struct {
|
||||
getHashes hashFetcherFn
|
||||
getBlocks blockFetcherFn
|
||||
}
|
||||
|
||||
func (ep extProt) GetHashes(hash common.Hash) error { return ep.getHashes(hash) }
|
||||
func (ep extProt) GetBlock(hashes []common.Hash) error { return ep.getBlocks(hashes) }
|
||||
|
||||
type ProtocolManager struct {
|
||||
mode Mode
|
||||
txpool txPool
|
||||
blockchain *core.BlockChain
|
||||
chaindb ethdb.Database
|
||||
@ -87,9 +83,10 @@ type ProtocolManager struct {
|
||||
|
||||
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
|
||||
// with the ethereum network.
|
||||
func NewProtocolManager(networkId int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) *ProtocolManager {
|
||||
func NewProtocolManager(mode Mode, networkId int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
|
||||
// Create the protocol manager with the base fields
|
||||
manager := &ProtocolManager{
|
||||
mode: mode,
|
||||
eventMux: mux,
|
||||
txpool: txpool,
|
||||
blockchain: blockchain,
|
||||
@ -100,11 +97,15 @@ func NewProtocolManager(networkId int, mux *event.TypeMux, txpool txPool, pow po
|
||||
quitSync: make(chan struct{}),
|
||||
}
|
||||
// Initiate a sub-protocol for every implemented version we can handle
|
||||
manager.SubProtocols = make([]p2p.Protocol, len(ProtocolVersions))
|
||||
for i := 0; i < len(manager.SubProtocols); i++ {
|
||||
version := ProtocolVersions[i]
|
||||
|
||||
manager.SubProtocols[i] = p2p.Protocol{
|
||||
manager.SubProtocols = make([]p2p.Protocol, 0, len(ProtocolVersions))
|
||||
for i, version := range ProtocolVersions {
|
||||
// Skip protocol version if incompatible with the mode of operation
|
||||
if minimumProtocolVersion[mode] > version {
|
||||
continue
|
||||
}
|
||||
// Compatible, initialize the sub-protocol
|
||||
version := version // Closure for the run
|
||||
manager.SubProtocols = append(manager.SubProtocols, p2p.Protocol{
|
||||
Name: "eth",
|
||||
Version: version,
|
||||
Length: ProtocolLengths[i],
|
||||
@ -113,7 +114,10 @@ func NewProtocolManager(networkId int, mux *event.TypeMux, txpool txPool, pow po
|
||||
manager.newPeerCh <- peer
|
||||
return manager.handle(peer)
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
if len(manager.SubProtocols) == 0 {
|
||||
return nil, errIncompatibleConfig
|
||||
}
|
||||
// Construct the different synchronisation mechanisms
|
||||
manager.downloader = downloader.New(manager.eventMux, manager.blockchain.HasBlock, manager.blockchain.GetBlock, manager.blockchain.CurrentBlock, manager.blockchain.GetTd, manager.blockchain.InsertChain, manager.removePeer)
|
||||
@ -126,7 +130,7 @@ func NewProtocolManager(networkId int, mux *event.TypeMux, txpool txPool, pow po
|
||||
}
|
||||
manager.fetcher = fetcher.New(manager.blockchain.GetBlock, validator, manager.BroadcastBlock, heighter, manager.blockchain.InsertChain, manager.removePeer)
|
||||
|
||||
return manager
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
func (pm *ProtocolManager) removePeer(id string) {
|
||||
|
@ -17,12 +17,42 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// Tests that protocol versions and modes of operations are matched up properly.
|
||||
func TestProtocolCompatibility(t *testing.T) {
|
||||
// Define the compatibility chart
|
||||
tests := []struct {
|
||||
version uint
|
||||
mode Mode
|
||||
compatible bool
|
||||
}{
|
||||
{61, ArchiveMode, true}, {62, ArchiveMode, true}, {63, ArchiveMode, true}, {64, ArchiveMode, true},
|
||||
{61, FullMode, false}, {62, FullMode, false}, {63, FullMode, true}, {64, FullMode, true},
|
||||
{61, LightMode, false}, {62, LightMode, false}, {63, LightMode, false}, {64, LightMode, true},
|
||||
}
|
||||
// Make sure anything we screw up is restored
|
||||
backup := ProtocolVersions
|
||||
defer func() { ProtocolVersions = backup }()
|
||||
|
||||
// Try all available compatibility configs and check for errors
|
||||
for i, tt := range tests {
|
||||
ProtocolVersions = []uint{tt.version}
|
||||
|
||||
pm, err := newTestProtocolManager(tt.mode, 0, nil, nil)
|
||||
if pm != nil {
|
||||
defer pm.Stop()
|
||||
}
|
||||
if (err == nil && !tt.compatible) || (err != nil && tt.compatible) {
|
||||
t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that hashes can be retrieved from a remote chain by hashes in reverse
|
||||
// order.
|
||||
func TestGetBlockHashes61(t *testing.T) { testGetBlockHashes(t, 61) }
|
||||
|
||||
func testGetBlockHashes(t *testing.T, protocol int) {
|
||||
pm := newTestProtocolManager(downloader.MaxHashFetch+15, nil, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, downloader.MaxHashFetch+15, nil, nil)
|
||||
peer, _ := newTestPeer("peer", protocol, pm, true)
|
||||
defer peer.close()
|
||||
|
||||
@ -65,7 +95,7 @@ func testGetBlockHashes(t *testing.T, protocol int) {
|
||||
func TestGetBlockHashesFromNumber61(t *testing.T) { testGetBlockHashesFromNumber(t, 61) }
|
||||
|
||||
func testGetBlockHashesFromNumber(t *testing.T, protocol int) {
|
||||
pm := newTestProtocolManager(downloader.MaxHashFetch+15, nil, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, downloader.MaxHashFetch+15, nil, nil)
|
||||
peer, _ := newTestPeer("peer", protocol, pm, true)
|
||||
defer peer.close()
|
||||
|
||||
@ -105,7 +135,7 @@ func testGetBlockHashesFromNumber(t *testing.T, protocol int) {
|
||||
func TestGetBlocks61(t *testing.T) { testGetBlocks(t, 61) }
|
||||
|
||||
func testGetBlocks(t *testing.T, protocol int) {
|
||||
pm := newTestProtocolManager(downloader.MaxHashFetch+15, nil, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, downloader.MaxHashFetch+15, nil, nil)
|
||||
peer, _ := newTestPeer("peer", protocol, pm, true)
|
||||
defer peer.close()
|
||||
|
||||
@ -177,7 +207,7 @@ func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
|
||||
func TestGetBlockHeaders64(t *testing.T) { testGetBlockHeaders(t, 64) }
|
||||
|
||||
func testGetBlockHeaders(t *testing.T, protocol int) {
|
||||
pm := newTestProtocolManager(downloader.MaxHashFetch+15, nil, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, downloader.MaxHashFetch+15, nil, nil)
|
||||
peer, _ := newTestPeer("peer", protocol, pm, true)
|
||||
defer peer.close()
|
||||
|
||||
@ -303,7 +333,7 @@ func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) }
|
||||
func TestGetBlockBodies64(t *testing.T) { testGetBlockBodies(t, 64) }
|
||||
|
||||
func testGetBlockBodies(t *testing.T, protocol int) {
|
||||
pm := newTestProtocolManager(downloader.MaxBlockFetch+15, nil, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, downloader.MaxBlockFetch+15, nil, nil)
|
||||
peer, _ := newTestPeer("peer", protocol, pm, true)
|
||||
defer peer.close()
|
||||
|
||||
@ -410,7 +440,7 @@ func testGetNodeData(t *testing.T, protocol int) {
|
||||
}
|
||||
}
|
||||
// Assemble the test environment
|
||||
pm := newTestProtocolManager(4, generator, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, 4, generator, nil)
|
||||
peer, _ := newTestPeer("peer", protocol, pm, true)
|
||||
defer peer.close()
|
||||
|
||||
@ -500,7 +530,7 @@ func testGetReceipt(t *testing.T, protocol int) {
|
||||
}
|
||||
}
|
||||
// Assemble the test environment
|
||||
pm := newTestProtocolManager(4, generator, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, 4, generator, nil)
|
||||
peer, _ := newTestPeer("peer", protocol, pm, true)
|
||||
defer peer.close()
|
||||
|
||||
|
@ -28,7 +28,7 @@ var (
|
||||
// newTestProtocolManager creates a new protocol manager for testing purposes,
|
||||
// with the given number of blocks already known, and potential notification
|
||||
// channels for different events.
|
||||
func newTestProtocolManager(blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) *ProtocolManager {
|
||||
func newTestProtocolManager(mode Mode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) {
|
||||
var (
|
||||
evmux = new(event.TypeMux)
|
||||
pow = new(core.FakePow)
|
||||
@ -42,8 +42,23 @@ func newTestProtocolManager(blocks int, generator func(int, *core.BlockGen), new
|
||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pm := NewProtocolManager(NetworkId, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
|
||||
pm, err := NewProtocolManager(mode, NetworkId, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pm.Start()
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
// newTestProtocolManagerMust creates a new protocol manager for testing purposes,
|
||||
// with the given number of blocks already known, and potential notification
|
||||
// channels for different events. In case of an error, the constructor force-
|
||||
// fails the test.
|
||||
func newTestProtocolManagerMust(t *testing.T, mode Mode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) *ProtocolManager {
|
||||
pm, err := newTestProtocolManager(mode, blocks, generator, newtx)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create protocol manager: %v", err)
|
||||
}
|
||||
return pm
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,15 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// Mode represents the mode of operation of the eth client.
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
ArchiveMode Mode = iota // Maintain the entire blockchain history
|
||||
FullMode // Maintain only a recent view of the blockchain
|
||||
LightMode // Don't maintain any history, rather fetch on demand
|
||||
)
|
||||
|
||||
// Constants to match up protocol versions and messages
|
||||
const (
|
||||
eth61 = 61
|
||||
@ -34,6 +43,14 @@ const (
|
||||
eth64 = 64
|
||||
)
|
||||
|
||||
// minimumProtocolVersion is the minimum version of the protocol eth must run to
|
||||
// support the desired mode of operation.
|
||||
var minimumProtocolVersion = map[Mode]uint{
|
||||
ArchiveMode: eth61,
|
||||
FullMode: eth63,
|
||||
LightMode: eth64,
|
||||
}
|
||||
|
||||
// Supported versions of the eth protocol (first is primary).
|
||||
var ProtocolVersions = []uint{eth64, eth63, eth62, eth61}
|
||||
|
||||
|
@ -44,7 +44,7 @@ func TestStatusMsgErrors63(t *testing.T) { testStatusMsgErrors(t, 63) }
|
||||
func TestStatusMsgErrors64(t *testing.T) { testStatusMsgErrors(t, 64) }
|
||||
|
||||
func testStatusMsgErrors(t *testing.T, protocol int) {
|
||||
pm := newTestProtocolManager(0, nil, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, 0, nil, nil)
|
||||
td, currentBlock, genesis := pm.blockchain.Status()
|
||||
defer pm.Stop()
|
||||
|
||||
@ -99,7 +99,7 @@ func TestRecvTransactions64(t *testing.T) { testRecvTransactions(t, 64) }
|
||||
|
||||
func testRecvTransactions(t *testing.T, protocol int) {
|
||||
txAdded := make(chan []*types.Transaction)
|
||||
pm := newTestProtocolManager(0, nil, txAdded)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, 0, nil, txAdded)
|
||||
p, _ := newTestPeer("peer", protocol, pm, true)
|
||||
defer pm.Stop()
|
||||
defer p.close()
|
||||
@ -127,7 +127,7 @@ func TestSendTransactions63(t *testing.T) { testSendTransactions(t, 63) }
|
||||
func TestSendTransactions64(t *testing.T) { testSendTransactions(t, 64) }
|
||||
|
||||
func testSendTransactions(t *testing.T, protocol int) {
|
||||
pm := newTestProtocolManager(0, nil, nil)
|
||||
pm := newTestProtocolManagerMust(t, ArchiveMode, 0, nil, nil)
|
||||
defer pm.Stop()
|
||||
|
||||
// Fill the pool with big transactions.
|
||||
|
Loading…
Reference in New Issue
Block a user