mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 18:30:45 +00:00
updated XDC WITH NEW MODE
This commit is contained in:
parent
5d7c5ef101
commit
cb8cf5b662
6 changed files with 1377 additions and 0 deletions
152
cmd/XDC/dao_test.go
Normal file
152
cmd/XDC/dao_test.go
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Genesis block for nodes which don't care about the DAO fork (i.e. not configured)
|
||||||
|
var daoOldGenesis = `{
|
||||||
|
"alloc" : {},
|
||||||
|
"coinbase" : "0x0000000000000000000000000000000000000000",
|
||||||
|
"difficulty" : "0x20000",
|
||||||
|
"extraData" : "",
|
||||||
|
"gasLimit" : "0x2fefd8",
|
||||||
|
"nonce" : "0x0000000000000042",
|
||||||
|
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"timestamp" : "0x00",
|
||||||
|
"config" : {}
|
||||||
|
}`
|
||||||
|
|
||||||
|
// Genesis block for nodes which actively oppose the DAO fork
|
||||||
|
var daoNoForkGenesis = `{
|
||||||
|
"alloc" : {},
|
||||||
|
"coinbase" : "0x0000000000000000000000000000000000000000",
|
||||||
|
"difficulty" : "0x20000",
|
||||||
|
"extraData" : "",
|
||||||
|
"gasLimit" : "0x2fefd8",
|
||||||
|
"nonce" : "0x0000000000000042",
|
||||||
|
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"timestamp" : "0x00",
|
||||||
|
"config" : {
|
||||||
|
"daoForkBlock" : 314,
|
||||||
|
"daoForkSupport" : false
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
// Genesis block for nodes which actively support the DAO fork
|
||||||
|
var daoProForkGenesis = `{
|
||||||
|
"alloc" : {},
|
||||||
|
"coinbase" : "0x0000000000000000000000000000000000000000",
|
||||||
|
"difficulty" : "0x20000",
|
||||||
|
"extraData" : "",
|
||||||
|
"gasLimit" : "0x2fefd8",
|
||||||
|
"nonce" : "0x0000000000000042",
|
||||||
|
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"timestamp" : "0x00",
|
||||||
|
"config" : {
|
||||||
|
"daoForkBlock" : 314,
|
||||||
|
"daoForkSupport" : true
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
var daoGenesisHash = common.HexToHash("5e1fc79cb4ffa4739177b5408045cd5d51c6cf766133f23f7cd72ee1f8d790e0")
|
||||||
|
var daoGenesisForkBlock = big.NewInt(314)
|
||||||
|
|
||||||
|
// TestDAOForkBlockNewChain tests that the DAO hard-fork number and the nodes support/opposition is correctly
|
||||||
|
// set in the database after various initialization procedures and invocations.
|
||||||
|
func TestDAOForkBlockNewChain(t *testing.T) {
|
||||||
|
for i, arg := range []struct {
|
||||||
|
genesis string
|
||||||
|
expectBlock *big.Int
|
||||||
|
expectVote bool
|
||||||
|
}{
|
||||||
|
// Test DAO Default Mainnet
|
||||||
|
{"", params.MainnetChainConfig.DAOForkBlock, true},
|
||||||
|
// test DAO Init Old Privnet
|
||||||
|
{daoOldGenesis, nil, false},
|
||||||
|
// test DAO Default No Fork Privnet
|
||||||
|
{daoNoForkGenesis, daoGenesisForkBlock, false},
|
||||||
|
// test DAO Default Pro Fork Privnet
|
||||||
|
{daoProForkGenesis, daoGenesisForkBlock, true},
|
||||||
|
} {
|
||||||
|
testDAOForkBlockNewChain(t, i, arg.genesis, arg.expectBlock, arg.expectVote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBlock *big.Int, expectVote bool) {
|
||||||
|
// Create a temporary data directory to use and inspect later
|
||||||
|
datadir := tmpdir(t)
|
||||||
|
defer os.RemoveAll(datadir)
|
||||||
|
|
||||||
|
// Start a Geth instance with the requested flags set and immediately terminate
|
||||||
|
if genesis != "" {
|
||||||
|
json := filepath.Join(datadir, "genesis.json")
|
||||||
|
if err := ioutil.WriteFile(json, []byte(genesis), 0600); err != nil {
|
||||||
|
t.Fatalf("test %d: failed to write genesis file: %v", test, err)
|
||||||
|
}
|
||||||
|
runGeth(t, "--datadir", datadir, "init", json).WaitExit()
|
||||||
|
} else {
|
||||||
|
// Force chain initialization
|
||||||
|
args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir}
|
||||||
|
geth := runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...)
|
||||||
|
geth.WaitExit()
|
||||||
|
}
|
||||||
|
// Retrieve the DAO config flag from the database
|
||||||
|
path := filepath.Join(datadir, "geth", "chaindata")
|
||||||
|
db, err := ethdb.NewLDBDatabase(path, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("test %d: failed to open test database: %v", test, err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
genesisHash := common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
|
||||||
|
if genesis != "" {
|
||||||
|
genesisHash = daoGenesisHash
|
||||||
|
}
|
||||||
|
config, err := core.GetChainConfig(db, genesisHash)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("test %d: failed to retrieve chain config: %v", test, err)
|
||||||
|
return // we want to return here, the other checks can't make it past this point (nil panic).
|
||||||
|
}
|
||||||
|
// Validate the DAO hard-fork block number against the expected value
|
||||||
|
if config.DAOForkBlock == nil {
|
||||||
|
if expectBlock != nil {
|
||||||
|
t.Errorf("test %d: dao hard-fork block mismatch: have nil, want %v", test, expectBlock)
|
||||||
|
}
|
||||||
|
} else if expectBlock == nil {
|
||||||
|
t.Errorf("test %d: dao hard-fork block mismatch: have %v, want nil", test, config.DAOForkBlock)
|
||||||
|
} else if config.DAOForkBlock.Cmp(expectBlock) != 0 {
|
||||||
|
t.Errorf("test %d: dao hard-fork block mismatch: have %v, want %v", test, config.DAOForkBlock, expectBlock)
|
||||||
|
}
|
||||||
|
if config.DAOForkSupport != expectVote {
|
||||||
|
t.Errorf("test %d: dao hard-fork support mismatch: have %v, want %v", test, config.DAOForkSupport, expectVote)
|
||||||
|
}
|
||||||
|
}
|
||||||
307
cmd/XDC/main.go
Normal file
307
cmd/XDC/main.go
Normal file
|
|
@ -0,0 +1,307 @@
|
||||||
|
// Copyright 2014 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// geth is the official command-line client for Ethereum.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/console"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
clientIdentifier = "geth" // Client identifier to advertise over the network
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Git SHA1 commit hash of the release (set via linker flags)
|
||||||
|
gitCommit = ""
|
||||||
|
|
||||||
|
// The app that holds all commands and flags.
|
||||||
|
app = utils.NewApp(gitCommit, "the go-ethereum command line interface")
|
||||||
|
// flags that configure the node
|
||||||
|
nodeFlags = []cli.Flag{
|
||||||
|
utils.IdentityFlag,
|
||||||
|
utils.UnlockedAccountFlag,
|
||||||
|
utils.PasswordFileFlag,
|
||||||
|
utils.BootnodesFlag,
|
||||||
|
utils.BootnodesV4Flag,
|
||||||
|
utils.BootnodesV5Flag,
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.KeyStoreDirFlag,
|
||||||
|
utils.NoUSBFlag,
|
||||||
|
utils.DashboardEnabledFlag,
|
||||||
|
utils.DashboardAddrFlag,
|
||||||
|
utils.DashboardPortFlag,
|
||||||
|
utils.DashboardRefreshFlag,
|
||||||
|
utils.EthashCacheDirFlag,
|
||||||
|
utils.EthashCachesInMemoryFlag,
|
||||||
|
utils.EthashCachesOnDiskFlag,
|
||||||
|
utils.EthashDatasetDirFlag,
|
||||||
|
utils.EthashDatasetsInMemoryFlag,
|
||||||
|
utils.EthashDatasetsOnDiskFlag,
|
||||||
|
utils.TxPoolNoLocalsFlag,
|
||||||
|
utils.TxPoolJournalFlag,
|
||||||
|
utils.TxPoolRejournalFlag,
|
||||||
|
utils.TxPoolPriceLimitFlag,
|
||||||
|
utils.TxPoolPriceBumpFlag,
|
||||||
|
utils.TxPoolAccountSlotsFlag,
|
||||||
|
utils.TxPoolGlobalSlotsFlag,
|
||||||
|
utils.TxPoolAccountQueueFlag,
|
||||||
|
utils.TxPoolGlobalQueueFlag,
|
||||||
|
utils.TxPoolLifetimeFlag,
|
||||||
|
utils.FastSyncFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.GCModeFlag,
|
||||||
|
utils.LightServFlag,
|
||||||
|
utils.LightPeersFlag,
|
||||||
|
utils.LightKDFFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.CacheDatabaseFlag,
|
||||||
|
utils.CacheGCFlag,
|
||||||
|
utils.TrieCacheGenFlag,
|
||||||
|
utils.ListenPortFlag,
|
||||||
|
utils.MaxPeersFlag,
|
||||||
|
utils.MaxPendingPeersFlag,
|
||||||
|
utils.EtherbaseFlag,
|
||||||
|
utils.GasPriceFlag,
|
||||||
|
utils.MinerThreadsFlag,
|
||||||
|
utils.MiningEnabledFlag,
|
||||||
|
utils.TargetGasLimitFlag,
|
||||||
|
utils.NATFlag,
|
||||||
|
utils.NoDiscoverFlag,
|
||||||
|
utils.DiscoveryV5Flag,
|
||||||
|
utils.NetrestrictFlag,
|
||||||
|
utils.NodeKeyFileFlag,
|
||||||
|
utils.NodeKeyHexFlag,
|
||||||
|
utils.DeveloperFlag,
|
||||||
|
utils.DeveloperPeriodFlag,
|
||||||
|
utils.TestnetFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
utils.VMEnableDebugFlag,
|
||||||
|
utils.NetworkIdFlag,
|
||||||
|
utils.RPCCORSDomainFlag,
|
||||||
|
utils.RPCVirtualHostsFlag,
|
||||||
|
utils.EthStatsURLFlag,
|
||||||
|
utils.MetricsEnabledFlag,
|
||||||
|
utils.FakePoWFlag,
|
||||||
|
utils.NoCompactionFlag,
|
||||||
|
utils.GpoBlocksFlag,
|
||||||
|
utils.GpoPercentileFlag,
|
||||||
|
utils.ExtraDataFlag,
|
||||||
|
configFileFlag,
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcFlags = []cli.Flag{
|
||||||
|
utils.RPCEnabledFlag,
|
||||||
|
utils.RPCListenAddrFlag,
|
||||||
|
utils.RPCPortFlag,
|
||||||
|
utils.RPCApiFlag,
|
||||||
|
utils.WSEnabledFlag,
|
||||||
|
utils.WSListenAddrFlag,
|
||||||
|
utils.WSPortFlag,
|
||||||
|
utils.WSApiFlag,
|
||||||
|
utils.WSAllowedOriginsFlag,
|
||||||
|
utils.IPCDisabledFlag,
|
||||||
|
utils.IPCPathFlag,
|
||||||
|
}
|
||||||
|
|
||||||
|
whisperFlags = []cli.Flag{
|
||||||
|
utils.WhisperEnabledFlag,
|
||||||
|
utils.WhisperMaxMessageSizeFlag,
|
||||||
|
utils.WhisperMinPOWFlag,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Initialize the CLI app and start Geth
|
||||||
|
app.Action = geth
|
||||||
|
app.HideVersion = true // we have a command to print the version
|
||||||
|
app.Copyright = "Copyright 2013-2017 The go-ethereum Authors"
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
// See chaincmd.go:
|
||||||
|
initCommand,
|
||||||
|
importCommand,
|
||||||
|
exportCommand,
|
||||||
|
importPreimagesCommand,
|
||||||
|
exportPreimagesCommand,
|
||||||
|
copydbCommand,
|
||||||
|
removedbCommand,
|
||||||
|
dumpCommand,
|
||||||
|
// See monitorcmd.go:
|
||||||
|
monitorCommand,
|
||||||
|
// See accountcmd.go:
|
||||||
|
accountCommand,
|
||||||
|
walletCommand,
|
||||||
|
// See consolecmd.go:
|
||||||
|
consoleCommand,
|
||||||
|
attachCommand,
|
||||||
|
javascriptCommand,
|
||||||
|
// See misccmd.go:
|
||||||
|
makecacheCommand,
|
||||||
|
makedagCommand,
|
||||||
|
versionCommand,
|
||||||
|
bugCommand,
|
||||||
|
licenseCommand,
|
||||||
|
// See config.go
|
||||||
|
dumpConfigCommand,
|
||||||
|
}
|
||||||
|
sort.Sort(cli.CommandsByName(app.Commands))
|
||||||
|
|
||||||
|
app.Flags = append(app.Flags, nodeFlags...)
|
||||||
|
app.Flags = append(app.Flags, rpcFlags...)
|
||||||
|
app.Flags = append(app.Flags, consoleFlags...)
|
||||||
|
app.Flags = append(app.Flags, debug.Flags...)
|
||||||
|
app.Flags = append(app.Flags, whisperFlags...)
|
||||||
|
|
||||||
|
app.Before = func(ctx *cli.Context) error {
|
||||||
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
if err := debug.Setup(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Start system runtime metrics collection
|
||||||
|
go metrics.CollectProcessMetrics(3 * time.Second)
|
||||||
|
|
||||||
|
utils.SetupNetwork(ctx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
app.After = func(ctx *cli.Context) error {
|
||||||
|
debug.Exit()
|
||||||
|
console.Stdin.Close() // Resets terminal mode.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// geth is the main entry point into the system if no special subcommand is ran.
|
||||||
|
// It creates a default node based on the command line arguments and runs it in
|
||||||
|
// blocking mode, waiting for it to be shut down.
|
||||||
|
func geth(ctx *cli.Context) error {
|
||||||
|
node := makeFullNode(ctx)
|
||||||
|
startNode(ctx, node)
|
||||||
|
node.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// startNode boots up the system node and all registered protocols, after which
|
||||||
|
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
|
||||||
|
// miner.
|
||||||
|
func startNode(ctx *cli.Context, stack *node.Node) {
|
||||||
|
// Start up the node itself
|
||||||
|
utils.StartNode(stack)
|
||||||
|
|
||||||
|
// Unlock any account specifically requested
|
||||||
|
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
|
||||||
|
|
||||||
|
passwords := utils.MakePasswordList(ctx)
|
||||||
|
unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
|
||||||
|
for i, account := range unlocks {
|
||||||
|
if trimmed := strings.TrimSpace(account); trimmed != "" {
|
||||||
|
unlockAccount(ctx, ks, trimmed, i, passwords)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Register wallet event handlers to open and auto-derive wallets
|
||||||
|
events := make(chan accounts.WalletEvent, 16)
|
||||||
|
stack.AccountManager().Subscribe(events)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// Create an chain state reader for self-derivation
|
||||||
|
rpcClient, err := stack.Attach()
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to attach to self: %v", err)
|
||||||
|
}
|
||||||
|
stateReader := ethclient.NewClient(rpcClient)
|
||||||
|
|
||||||
|
// Open any wallets already attached
|
||||||
|
for _, wallet := range stack.AccountManager().Wallets() {
|
||||||
|
if err := wallet.Open(""); err != nil {
|
||||||
|
log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Listen for wallet event till termination
|
||||||
|
for event := range events {
|
||||||
|
switch event.Kind {
|
||||||
|
case accounts.WalletArrived:
|
||||||
|
if err := event.Wallet.Open(""); err != nil {
|
||||||
|
log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
|
||||||
|
}
|
||||||
|
case accounts.WalletOpened:
|
||||||
|
status, _ := event.Wallet.Status()
|
||||||
|
log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
|
||||||
|
|
||||||
|
if event.Wallet.URL().Scheme == "ledger" {
|
||||||
|
event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader)
|
||||||
|
} else {
|
||||||
|
event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
|
||||||
|
}
|
||||||
|
|
||||||
|
case accounts.WalletDropped:
|
||||||
|
log.Info("Old wallet dropped", "url", event.Wallet.URL())
|
||||||
|
event.Wallet.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// Start auxiliary services if enabled
|
||||||
|
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
|
||||||
|
// Mining only makes sense if a full Ethereum node is running
|
||||||
|
if ctx.GlobalBool(utils.LightModeFlag.Name) || ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
|
||||||
|
utils.Fatalf("Light clients do not support mining")
|
||||||
|
}
|
||||||
|
var ethereum *eth.Ethereum
|
||||||
|
if err := stack.Service(ðereum); err != nil {
|
||||||
|
utils.Fatalf("Ethereum service not running: %v", err)
|
||||||
|
}
|
||||||
|
// Use a reduced number of threads if requested
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set the gas price to the limits from the CLI and start mining
|
||||||
|
ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name))
|
||||||
|
if err := ethereum.StartMining(true); err != nil {
|
||||||
|
utils.Fatalf("Failed to start mining: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
139
cmd/XDC/misccmd.go
Normal file
139
cmd/XDC/misccmd.go
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"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"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
makecacheCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(makecache),
|
||||||
|
Name: "makecache",
|
||||||
|
Usage: "Generate ethash verification cache (for testing)",
|
||||||
|
ArgsUsage: "<blockNum> <outputDir>",
|
||||||
|
Category: "MISCELLANEOUS COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The makecache command generates an ethash cache in <outputDir>.
|
||||||
|
|
||||||
|
This command exists to support the system testing project.
|
||||||
|
Regular users do not need to execute it.
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
makedagCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(makedag),
|
||||||
|
Name: "makedag",
|
||||||
|
Usage: "Generate ethash mining DAG (for testing)",
|
||||||
|
ArgsUsage: "<blockNum> <outputDir>",
|
||||||
|
Category: "MISCELLANEOUS COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The makedag command generates an ethash DAG in <outputDir>.
|
||||||
|
|
||||||
|
This command exists to support the system testing project.
|
||||||
|
Regular users do not need to execute it.
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
versionCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(version),
|
||||||
|
Name: "version",
|
||||||
|
Usage: "Print version numbers",
|
||||||
|
ArgsUsage: " ",
|
||||||
|
Category: "MISCELLANEOUS COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The output of this command is supposed to be machine-readable.
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
licenseCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(license),
|
||||||
|
Name: "license",
|
||||||
|
Usage: "Display license information",
|
||||||
|
ArgsUsage: " ",
|
||||||
|
Category: "MISCELLANEOUS COMMANDS",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// makecache generates an ethash verification cache into the provided folder.
|
||||||
|
func makecache(ctx *cli.Context) error {
|
||||||
|
args := ctx.Args()
|
||||||
|
if len(args) != 2 {
|
||||||
|
utils.Fatalf(`Usage: geth makecache <block number> <outputdir>`)
|
||||||
|
}
|
||||||
|
block, err := strconv.ParseUint(args[0], 0, 64)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Invalid block number: %v", err)
|
||||||
|
}
|
||||||
|
ethash.MakeCache(block, args[1])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makedag generates an ethash mining DAG into the provided folder.
|
||||||
|
func makedag(ctx *cli.Context) error {
|
||||||
|
args := ctx.Args()
|
||||||
|
if len(args) != 2 {
|
||||||
|
utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`)
|
||||||
|
}
|
||||||
|
block, err := strconv.ParseUint(args[0], 0, 64)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Invalid block number: %v", err)
|
||||||
|
}
|
||||||
|
ethash.MakeDataset(block, args[1])
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func version(ctx *cli.Context) error {
|
||||||
|
fmt.Println(strings.Title(clientIdentifier))
|
||||||
|
fmt.Println("Version:", params.Version)
|
||||||
|
if gitCommit != "" {
|
||||||
|
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)
|
||||||
|
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
|
||||||
|
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func license(_ *cli.Context) error {
|
||||||
|
fmt.Println(`Geth is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Geth 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with geth. If not, see <http://www.gnu.org/licenses/>.`)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
351
cmd/XDC/monitorcmd.go
Normal file
351
cmd/XDC/monitorcmd.go
Normal file
|
|
@ -0,0 +1,351 @@
|
||||||
|
// Copyright 2015 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/gizak/termui"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
monitorCommandAttachFlag = cli.StringFlag{
|
||||||
|
Name: "attach",
|
||||||
|
Value: node.DefaultIPCEndpoint(clientIdentifier),
|
||||||
|
Usage: "API endpoint to attach to",
|
||||||
|
}
|
||||||
|
monitorCommandRowsFlag = cli.IntFlag{
|
||||||
|
Name: "rows",
|
||||||
|
Value: 5,
|
||||||
|
Usage: "Maximum rows in the chart grid",
|
||||||
|
}
|
||||||
|
monitorCommandRefreshFlag = cli.IntFlag{
|
||||||
|
Name: "refresh",
|
||||||
|
Value: 3,
|
||||||
|
Usage: "Refresh interval in seconds",
|
||||||
|
}
|
||||||
|
monitorCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(monitor), // keep track of migration progress
|
||||||
|
Name: "monitor",
|
||||||
|
Usage: "Monitor and visualize node metrics",
|
||||||
|
ArgsUsage: " ",
|
||||||
|
Category: "MONITOR COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The Geth monitor is a tool to collect and visualize various internal metrics
|
||||||
|
gathered by the node, supporting different chart types as well as the capacity
|
||||||
|
to display multiple metrics simultaneously.
|
||||||
|
`,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
monitorCommandAttachFlag,
|
||||||
|
monitorCommandRowsFlag,
|
||||||
|
monitorCommandRefreshFlag,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// monitor starts a terminal UI based monitoring tool for the requested metrics.
|
||||||
|
func monitor(ctx *cli.Context) error {
|
||||||
|
var (
|
||||||
|
client *rpc.Client
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
// Attach to an Ethereum node over IPC or RPC
|
||||||
|
endpoint := ctx.String(monitorCommandAttachFlag.Name)
|
||||||
|
if client, err = dialRPC(endpoint); err != nil {
|
||||||
|
utils.Fatalf("Unable to attach to geth node: %v", err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
// Retrieve all the available metrics and resolve the user pattens
|
||||||
|
metrics, err := retrieveMetrics(client)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to retrieve system metrics: %v", err)
|
||||||
|
}
|
||||||
|
monitored := resolveMetrics(metrics, ctx.Args())
|
||||||
|
if len(monitored) == 0 {
|
||||||
|
list := expandMetrics(metrics, "")
|
||||||
|
sort.Strings(list)
|
||||||
|
|
||||||
|
if len(list) > 0 {
|
||||||
|
utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - "))
|
||||||
|
} else {
|
||||||
|
utils.Fatalf("No metrics collected by geth (--%s).\n", utils.MetricsEnabledFlag.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(monitored)
|
||||||
|
if cols := len(monitored) / ctx.Int(monitorCommandRowsFlag.Name); cols > 6 {
|
||||||
|
utils.Fatalf("Requested metrics (%d) spans more that 6 columns:\n - %s", len(monitored), strings.Join(monitored, "\n - "))
|
||||||
|
}
|
||||||
|
// Create and configure the chart UI defaults
|
||||||
|
if err := termui.Init(); err != nil {
|
||||||
|
utils.Fatalf("Unable to initialize terminal UI: %v", err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
rows := len(monitored)
|
||||||
|
if max := ctx.Int(monitorCommandRowsFlag.Name); rows > max {
|
||||||
|
rows = max
|
||||||
|
}
|
||||||
|
cols := (len(monitored) + rows - 1) / rows
|
||||||
|
for i := 0; i < rows; i++ {
|
||||||
|
termui.Body.AddRows(termui.NewRow())
|
||||||
|
}
|
||||||
|
// Create each individual data chart
|
||||||
|
footer := termui.NewPar("")
|
||||||
|
footer.Block.Border = true
|
||||||
|
footer.Height = 3
|
||||||
|
|
||||||
|
charts := make([]*termui.LineChart, len(monitored))
|
||||||
|
units := make([]int, len(monitored))
|
||||||
|
data := make([][]float64, len(monitored))
|
||||||
|
for i := 0; i < len(monitored); i++ {
|
||||||
|
charts[i] = createChart((termui.TermHeight() - footer.Height) / rows)
|
||||||
|
row := termui.Body.Rows[i%rows]
|
||||||
|
row.Cols = append(row.Cols, termui.NewCol(12/cols, 0, charts[i]))
|
||||||
|
}
|
||||||
|
termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer)))
|
||||||
|
|
||||||
|
refreshCharts(client, monitored, data, units, charts, ctx, footer)
|
||||||
|
termui.Body.Align()
|
||||||
|
termui.Render(termui.Body)
|
||||||
|
|
||||||
|
// Watch for various system events, and periodically refresh the charts
|
||||||
|
termui.Handle("/sys/kbd/C-c", func(termui.Event) {
|
||||||
|
termui.StopLoop()
|
||||||
|
})
|
||||||
|
termui.Handle("/sys/wnd/resize", func(termui.Event) {
|
||||||
|
termui.Body.Width = termui.TermWidth()
|
||||||
|
for _, chart := range charts {
|
||||||
|
chart.Height = (termui.TermHeight() - footer.Height) / rows
|
||||||
|
}
|
||||||
|
termui.Body.Align()
|
||||||
|
termui.Render(termui.Body)
|
||||||
|
})
|
||||||
|
go func() {
|
||||||
|
tick := time.NewTicker(time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second)
|
||||||
|
for range tick.C {
|
||||||
|
if refreshCharts(client, monitored, data, units, charts, ctx, footer) {
|
||||||
|
termui.Body.Align()
|
||||||
|
}
|
||||||
|
termui.Render(termui.Body)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
termui.Loop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieveMetrics contacts the attached geth node and retrieves the entire set
|
||||||
|
// of collected system metrics.
|
||||||
|
func retrieveMetrics(client *rpc.Client) (map[string]interface{}, error) {
|
||||||
|
var metrics map[string]interface{}
|
||||||
|
err := client.Call(&metrics, "debug_metrics", true)
|
||||||
|
return metrics, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveMetrics takes a list of input metric patterns, and resolves each to one
|
||||||
|
// or more canonical metric names.
|
||||||
|
func resolveMetrics(metrics map[string]interface{}, patterns []string) []string {
|
||||||
|
res := []string{}
|
||||||
|
for _, pattern := range patterns {
|
||||||
|
res = append(res, resolveMetric(metrics, pattern, "")...)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveMetrics takes a single of input metric pattern, and resolves it to one
|
||||||
|
// or more canonical metric names.
|
||||||
|
func resolveMetric(metrics map[string]interface{}, pattern string, path string) []string {
|
||||||
|
results := []string{}
|
||||||
|
|
||||||
|
// If a nested metric was requested, recurse optionally branching (via comma)
|
||||||
|
parts := strings.SplitN(pattern, "/", 2)
|
||||||
|
if len(parts) > 1 {
|
||||||
|
for _, variation := range strings.Split(parts[0], ",") {
|
||||||
|
if submetrics, ok := metrics[variation].(map[string]interface{}); !ok {
|
||||||
|
utils.Fatalf("Failed to retrieve system metrics: %s", path+variation)
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
// Depending what the last link is, return or expand
|
||||||
|
for _, variation := range strings.Split(pattern, ",") {
|
||||||
|
switch metric := metrics[variation].(type) {
|
||||||
|
case float64:
|
||||||
|
// Final metric value found, return as singleton
|
||||||
|
results = append(results, path+variation)
|
||||||
|
|
||||||
|
case map[string]interface{}:
|
||||||
|
results = append(results, expandMetrics(metric, path+variation+"/")...)
|
||||||
|
|
||||||
|
default:
|
||||||
|
utils.Fatalf("Metric pattern resolved to unexpected type: %v", reflect.TypeOf(metric))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// expandMetrics expands the entire tree of metrics into a flat list of paths.
|
||||||
|
func expandMetrics(metrics map[string]interface{}, path string) []string {
|
||||||
|
// Iterate over all fields and expand individually
|
||||||
|
list := []string{}
|
||||||
|
for name, metric := range metrics {
|
||||||
|
switch metric := metric.(type) {
|
||||||
|
case float64:
|
||||||
|
// Final metric value found, append to list
|
||||||
|
list = append(list, path+name)
|
||||||
|
|
||||||
|
case map[string]interface{}:
|
||||||
|
// Tree of metrics found, expand recursively
|
||||||
|
list = append(list, expandMetrics(metric, path+name+"/")...)
|
||||||
|
|
||||||
|
default:
|
||||||
|
utils.Fatalf("Metric pattern %s resolved to unexpected type: %v", path+name, reflect.TypeOf(metric))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchMetric iterates over the metrics map and retrieves a specific one.
|
||||||
|
func fetchMetric(metrics map[string]interface{}, metric string) float64 {
|
||||||
|
parts := strings.Split(metric, "/")
|
||||||
|
for _, part := range parts[:len(parts)-1] {
|
||||||
|
var found bool
|
||||||
|
metrics, found = metrics[part].(map[string]interface{})
|
||||||
|
if !found {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v, ok := metrics[parts[len(parts)-1]].(float64); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// refreshCharts retrieves a next batch of metrics, and inserts all the new
|
||||||
|
// values into the active datasets and charts
|
||||||
|
func refreshCharts(client *rpc.Client, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) {
|
||||||
|
values, err := retrieveMetrics(client)
|
||||||
|
for i, metric := range metrics {
|
||||||
|
if len(data) < 512 {
|
||||||
|
data[i] = append([]float64{fetchMetric(values, metric)}, data[i]...)
|
||||||
|
} else {
|
||||||
|
data[i] = append([]float64{fetchMetric(values, metric)}, data[i][:len(data[i])-1]...)
|
||||||
|
}
|
||||||
|
if updateChart(metric, data[i], &units[i], charts[i], err) {
|
||||||
|
realign = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateFooter(ctx, err, footer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateChart inserts a dataset into a line chart, scaling appropriately as to
|
||||||
|
// not display weird labels, also updating the chart label accordingly.
|
||||||
|
func updateChart(metric string, data []float64, base *int, chart *termui.LineChart, err error) (realign bool) {
|
||||||
|
dataUnits := []string{"", "K", "M", "G", "T", "E"}
|
||||||
|
timeUnits := []string{"ns", "µs", "ms", "s", "ks", "ms"}
|
||||||
|
colors := []termui.Attribute{termui.ColorBlue, termui.ColorCyan, termui.ColorGreen, termui.ColorYellow, termui.ColorRed, termui.ColorRed}
|
||||||
|
|
||||||
|
// Extract only part of the data that's actually visible
|
||||||
|
if chart.Width*2 < len(data) {
|
||||||
|
data = data[:chart.Width*2]
|
||||||
|
}
|
||||||
|
// Find the maximum value and scale under 1K
|
||||||
|
high := 0.0
|
||||||
|
if len(data) > 0 {
|
||||||
|
high = data[0]
|
||||||
|
for _, value := range data[1:] {
|
||||||
|
high = math.Max(high, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unit, scale := 0, 1.0
|
||||||
|
for high >= 1000 && unit+1 < len(dataUnits) {
|
||||||
|
high, unit, scale = high/1000, unit+1, scale*1000
|
||||||
|
}
|
||||||
|
// If the unit changes, re-create the chart (hack to set max height...)
|
||||||
|
if unit != *base {
|
||||||
|
realign, *base, *chart = true, unit, *createChart(chart.Height)
|
||||||
|
}
|
||||||
|
// Update the chart's data points with the scaled values
|
||||||
|
if cap(chart.Data) < len(data) {
|
||||||
|
chart.Data = make([]float64, len(data))
|
||||||
|
}
|
||||||
|
chart.Data = chart.Data[:len(data)]
|
||||||
|
for i, value := range data {
|
||||||
|
chart.Data[i] = value / scale
|
||||||
|
}
|
||||||
|
// Update the chart's label with the scale units
|
||||||
|
units := dataUnits
|
||||||
|
if strings.Contains(metric, "/Percentiles/") || strings.Contains(metric, "/pauses/") || strings.Contains(metric, "/time/") {
|
||||||
|
units = timeUnits
|
||||||
|
}
|
||||||
|
chart.BorderLabel = metric
|
||||||
|
if len(units[unit]) > 0 {
|
||||||
|
chart.BorderLabel += " [" + units[unit] + "]"
|
||||||
|
}
|
||||||
|
chart.LineColor = colors[unit] | termui.AttrBold
|
||||||
|
if err != nil {
|
||||||
|
chart.LineColor = termui.ColorRed | termui.AttrBold
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// createChart creates an empty line chart with the default configs.
|
||||||
|
func createChart(height int) *termui.LineChart {
|
||||||
|
chart := termui.NewLineChart()
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
chart.Mode = "dot"
|
||||||
|
}
|
||||||
|
chart.DataLabels = []string{""}
|
||||||
|
chart.Height = height
|
||||||
|
chart.AxesColor = termui.ColorWhite
|
||||||
|
chart.PaddingBottom = -2
|
||||||
|
|
||||||
|
chart.BorderLabelFg = chart.BorderFg | termui.AttrBold
|
||||||
|
chart.BorderFg = chart.BorderBg
|
||||||
|
|
||||||
|
return chart
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateFooter updates the footer contents based on any encountered errors.
|
||||||
|
func updateFooter(ctx *cli.Context, err error, footer *termui.Par) {
|
||||||
|
// Generate the basic footer
|
||||||
|
refresh := time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second
|
||||||
|
footer.Text = fmt.Sprintf("Press Ctrl+C to quit. Refresh interval: %v.", refresh)
|
||||||
|
footer.TextFgColor = termui.ThemeAttr("par.fg") | termui.AttrBold
|
||||||
|
|
||||||
|
// Append any encountered errors
|
||||||
|
if err != nil {
|
||||||
|
footer.Text = fmt.Sprintf("Error: %v.", err)
|
||||||
|
footer.TextFgColor = termui.ColorRed | termui.AttrBold
|
||||||
|
}
|
||||||
|
}
|
||||||
98
cmd/XDC/run_test.go
Normal file
98
cmd/XDC/run_test.go
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/reexec"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/cmdtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func tmpdir(t *testing.T) string {
|
||||||
|
dir, err := ioutil.TempDir("", "geth-test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
type testgeth struct {
|
||||||
|
*cmdtest.TestCmd
|
||||||
|
|
||||||
|
// template variables for expect
|
||||||
|
Datadir string
|
||||||
|
Etherbase string
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Run the app if we've been exec'd as "geth-test" in runGeth.
|
||||||
|
reexec.Register("geth-test", func() {
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
// check if we have been reexec'd
|
||||||
|
if reexec.Init() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
// spawns geth with the given command line args. If the args don't set --datadir, the
|
||||||
|
// child g gets a temporary data directory.
|
||||||
|
func runGeth(t *testing.T, args ...string) *testgeth {
|
||||||
|
tt := &testgeth{}
|
||||||
|
tt.TestCmd = cmdtest.NewTestCmd(t, tt)
|
||||||
|
for i, arg := range args {
|
||||||
|
switch {
|
||||||
|
case arg == "-datadir" || arg == "--datadir":
|
||||||
|
if i < len(args)-1 {
|
||||||
|
tt.Datadir = args[i+1]
|
||||||
|
}
|
||||||
|
case arg == "-etherbase" || arg == "--etherbase":
|
||||||
|
if i < len(args)-1 {
|
||||||
|
tt.Etherbase = args[i+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tt.Datadir == "" {
|
||||||
|
tt.Datadir = tmpdir(t)
|
||||||
|
tt.Cleanup = func() { os.RemoveAll(tt.Datadir) }
|
||||||
|
args = append([]string{"-datadir", tt.Datadir}, args...)
|
||||||
|
// Remove the temporary datadir if something fails below.
|
||||||
|
defer func() {
|
||||||
|
if t.Failed() {
|
||||||
|
tt.Cleanup()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boot "geth". This actually runs the test binary but the TestMain
|
||||||
|
// function will prevent any tests from running.
|
||||||
|
tt.Run("geth-test", args...)
|
||||||
|
|
||||||
|
return tt
|
||||||
|
}
|
||||||
330
cmd/XDC/usage.go
Normal file
330
cmd/XDC/usage.go
Normal file
|
|
@ -0,0 +1,330 @@
|
||||||
|
// Copyright 2015 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains the geth command usage template and generator.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AppHelpTemplate is the test template for the default, global app help topic.
|
||||||
|
var AppHelpTemplate = `NAME:
|
||||||
|
{{.App.Name}} - {{.App.Usage}}
|
||||||
|
|
||||||
|
Copyright 2013-2017 The go-ethereum Authors
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
{{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||||
|
{{if .App.Version}}
|
||||||
|
VERSION:
|
||||||
|
{{.App.Version}}
|
||||||
|
{{end}}{{if len .App.Authors}}
|
||||||
|
AUTHOR(S):
|
||||||
|
{{range .App.Authors}}{{ . }}{{end}}
|
||||||
|
{{end}}{{if .App.Commands}}
|
||||||
|
COMMANDS:
|
||||||
|
{{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
|
||||||
|
{{end}}{{end}}{{if .FlagGroups}}
|
||||||
|
{{range .FlagGroups}}{{.Name}} OPTIONS:
|
||||||
|
{{range .Flags}}{{.}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}{{end}}{{if .App.Copyright }}
|
||||||
|
COPYRIGHT:
|
||||||
|
{{.App.Copyright}}
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
|
// flagGroup is a collection of flags belonging to a single topic.
|
||||||
|
type flagGroup struct {
|
||||||
|
Name string
|
||||||
|
Flags []cli.Flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppHelpFlagGroups is the application flags, grouped by functionality.
|
||||||
|
var AppHelpFlagGroups = []flagGroup{
|
||||||
|
{
|
||||||
|
Name: "ETHEREUM",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
configFileFlag,
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.KeyStoreDirFlag,
|
||||||
|
utils.NoUSBFlag,
|
||||||
|
utils.NetworkIdFlag,
|
||||||
|
utils.TestnetFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.GCModeFlag,
|
||||||
|
utils.EthStatsURLFlag,
|
||||||
|
utils.IdentityFlag,
|
||||||
|
utils.LightServFlag,
|
||||||
|
utils.LightPeersFlag,
|
||||||
|
utils.LightKDFFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{Name: "DEVELOPER CHAIN",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DeveloperFlag,
|
||||||
|
utils.DeveloperPeriodFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ETHASH",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.EthashCacheDirFlag,
|
||||||
|
utils.EthashCachesInMemoryFlag,
|
||||||
|
utils.EthashCachesOnDiskFlag,
|
||||||
|
utils.EthashDatasetDirFlag,
|
||||||
|
utils.EthashDatasetsInMemoryFlag,
|
||||||
|
utils.EthashDatasetsOnDiskFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
//{
|
||||||
|
// Name: "DASHBOARD",
|
||||||
|
// Flags: []cli.Flag{
|
||||||
|
// utils.DashboardEnabledFlag,
|
||||||
|
// utils.DashboardAddrFlag,
|
||||||
|
// utils.DashboardPortFlag,
|
||||||
|
// utils.DashboardRefreshFlag,
|
||||||
|
// utils.DashboardAssetsFlag,
|
||||||
|
// },
|
||||||
|
//},
|
||||||
|
{
|
||||||
|
Name: "TRANSACTION POOL",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.TxPoolNoLocalsFlag,
|
||||||
|
utils.TxPoolJournalFlag,
|
||||||
|
utils.TxPoolRejournalFlag,
|
||||||
|
utils.TxPoolPriceLimitFlag,
|
||||||
|
utils.TxPoolPriceBumpFlag,
|
||||||
|
utils.TxPoolAccountSlotsFlag,
|
||||||
|
utils.TxPoolGlobalSlotsFlag,
|
||||||
|
utils.TxPoolAccountQueueFlag,
|
||||||
|
utils.TxPoolGlobalQueueFlag,
|
||||||
|
utils.TxPoolLifetimeFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PERFORMANCE TUNING",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.CacheDatabaseFlag,
|
||||||
|
utils.CacheGCFlag,
|
||||||
|
utils.TrieCacheGenFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ACCOUNT",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.UnlockedAccountFlag,
|
||||||
|
utils.PasswordFileFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "API AND CONSOLE",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.RPCEnabledFlag,
|
||||||
|
utils.RPCListenAddrFlag,
|
||||||
|
utils.RPCPortFlag,
|
||||||
|
utils.RPCApiFlag,
|
||||||
|
utils.WSEnabledFlag,
|
||||||
|
utils.WSListenAddrFlag,
|
||||||
|
utils.WSPortFlag,
|
||||||
|
utils.WSApiFlag,
|
||||||
|
utils.WSAllowedOriginsFlag,
|
||||||
|
utils.IPCDisabledFlag,
|
||||||
|
utils.IPCPathFlag,
|
||||||
|
utils.RPCCORSDomainFlag,
|
||||||
|
utils.RPCVirtualHostsFlag,
|
||||||
|
utils.JSpathFlag,
|
||||||
|
utils.ExecFlag,
|
||||||
|
utils.PreloadJSFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "NETWORKING",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.BootnodesFlag,
|
||||||
|
utils.BootnodesV4Flag,
|
||||||
|
utils.BootnodesV5Flag,
|
||||||
|
utils.ListenPortFlag,
|
||||||
|
utils.MaxPeersFlag,
|
||||||
|
utils.MaxPendingPeersFlag,
|
||||||
|
utils.NATFlag,
|
||||||
|
utils.NoDiscoverFlag,
|
||||||
|
utils.DiscoveryV5Flag,
|
||||||
|
utils.NetrestrictFlag,
|
||||||
|
utils.NodeKeyFileFlag,
|
||||||
|
utils.NodeKeyHexFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "MINER",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.MiningEnabledFlag,
|
||||||
|
utils.MinerThreadsFlag,
|
||||||
|
utils.EtherbaseFlag,
|
||||||
|
utils.TargetGasLimitFlag,
|
||||||
|
utils.GasPriceFlag,
|
||||||
|
utils.ExtraDataFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "GAS PRICE ORACLE",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.GpoBlocksFlag,
|
||||||
|
utils.GpoPercentileFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "VIRTUAL MACHINE",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.VMEnableDebugFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "LOGGING AND DEBUGGING",
|
||||||
|
Flags: append([]cli.Flag{
|
||||||
|
utils.MetricsEnabledFlag,
|
||||||
|
utils.FakePoWFlag,
|
||||||
|
utils.NoCompactionFlag,
|
||||||
|
}, debug.Flags...),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "WHISPER (EXPERIMENTAL)",
|
||||||
|
Flags: whisperFlags,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "DEPRECATED",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.FastSyncFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "MISC",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// byCategory sorts an array of flagGroup by Name in the order
|
||||||
|
// defined in AppHelpFlagGroups.
|
||||||
|
type byCategory []flagGroup
|
||||||
|
|
||||||
|
func (a byCategory) Len() int { return len(a) }
|
||||||
|
func (a byCategory) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
func (a byCategory) Less(i, j int) bool {
|
||||||
|
iCat, jCat := a[i].Name, a[j].Name
|
||||||
|
iIdx, jIdx := len(AppHelpFlagGroups), len(AppHelpFlagGroups) // ensure non categorized flags come last
|
||||||
|
|
||||||
|
for i, group := range AppHelpFlagGroups {
|
||||||
|
if iCat == group.Name {
|
||||||
|
iIdx = i
|
||||||
|
}
|
||||||
|
if jCat == group.Name {
|
||||||
|
jIdx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return iIdx < jIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagCategory(flag cli.Flag) string {
|
||||||
|
for _, category := range AppHelpFlagGroups {
|
||||||
|
for _, flg := range category.Flags {
|
||||||
|
if flg.GetName() == flag.GetName() {
|
||||||
|
return category.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "MISC"
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Override the default app help template
|
||||||
|
cli.AppHelpTemplate = AppHelpTemplate
|
||||||
|
|
||||||
|
// Define a one shot struct to pass to the usage template
|
||||||
|
type helpData struct {
|
||||||
|
App interface{}
|
||||||
|
FlagGroups []flagGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the default app help printer, but only for the global app help
|
||||||
|
originalHelpPrinter := cli.HelpPrinter
|
||||||
|
cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) {
|
||||||
|
if tmpl == AppHelpTemplate {
|
||||||
|
// Iterate over all the flags and add any uncategorized ones
|
||||||
|
categorized := make(map[string]struct{})
|
||||||
|
for _, group := range AppHelpFlagGroups {
|
||||||
|
for _, flag := range group.Flags {
|
||||||
|
categorized[flag.String()] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uncategorized := []cli.Flag{}
|
||||||
|
for _, flag := range data.(*cli.App).Flags {
|
||||||
|
if _, ok := categorized[flag.String()]; !ok {
|
||||||
|
if strings.HasPrefix(flag.GetName(), "dashboard") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
uncategorized = append(uncategorized, flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(uncategorized) > 0 {
|
||||||
|
// Append all ungategorized options to the misc group
|
||||||
|
miscs := len(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags)
|
||||||
|
AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = append(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags, uncategorized...)
|
||||||
|
|
||||||
|
// Make sure they are removed afterwards
|
||||||
|
defer func() {
|
||||||
|
AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags[:miscs]
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
// Render out custom usage screen
|
||||||
|
originalHelpPrinter(w, tmpl, helpData{data, AppHelpFlagGroups})
|
||||||
|
} else if tmpl == utils.CommandHelpTemplate {
|
||||||
|
// Iterate over all command specific flags and categorize them
|
||||||
|
categorized := make(map[string][]cli.Flag)
|
||||||
|
for _, flag := range data.(cli.Command).Flags {
|
||||||
|
if _, ok := categorized[flag.String()]; !ok {
|
||||||
|
categorized[flagCategory(flag)] = append(categorized[flagCategory(flag)], flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort to get a stable ordering
|
||||||
|
sorted := make([]flagGroup, 0, len(categorized))
|
||||||
|
for cat, flgs := range categorized {
|
||||||
|
sorted = append(sorted, flagGroup{cat, flgs})
|
||||||
|
}
|
||||||
|
sort.Sort(byCategory(sorted))
|
||||||
|
|
||||||
|
// add sorted array to data and render with default printer
|
||||||
|
originalHelpPrinter(w, tmpl, map[string]interface{}{
|
||||||
|
"cmd": data,
|
||||||
|
"categorizedFlags": sorted,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
originalHelpPrinter(w, tmpl, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue