cmd: migrate to urfave/cli/v2 (#24751)

This change updates our urfave/cli dependency to the v2 branch of the library.
There are some Go API changes in cli v2:

- Flag values can now be accessed using the methods ctx.Bool,
  ctx.Int, ctx.String, ... regardless of whether the flag is 'local' or
  'global'.

- v2 has built-in support for flag categories. Our home-grown category
  system is removed and the categories of flags are assigned as part of
  the flag definition.

For users, there is only one observable difference with cli v2: flags must now
strictly appear before regular arguments. For example, the following command is
now invalid:

   geth account import mykey.json --password file.txt

Instead, the command must be invoked as follows:

   geth account import --password file.txt mykey.json
This commit is contained in:
willian.eth 2022-06-27 18:22:36 +02:00 committed by GitHub
parent 119f955686
commit 52ed3570c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 2353 additions and 2320 deletions

View File

@ -224,6 +224,9 @@ func doInstall(cmdline []string) {
gobuild.Args = append(gobuild.Args, "-p", "1") gobuild.Args = append(gobuild.Args, "-p", "1")
} }
// Disable CLI markdown doc generation in release builds.
gobuild.Args = append(gobuild.Args, "-tags", "urfave_cli_no_docs")
// We use -trimpath to avoid leaking local paths into the built executables. // We use -trimpath to avoid leaking local paths into the built executables.
gobuild.Args = append(gobuild.Args, "-trimpath") gobuild.Args = append(gobuild.Args, "-trimpath")

View File

@ -0,0 +1,21 @@
#! /bin/bash
: ${PROG:=$(basename ${BASH_SOURCE})}
_cli_bash_autocomplete() {
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == "-"* ]]; then
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
else
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
fi
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG
unset PROG

View File

@ -0,0 +1,20 @@
#compdef $PROG
_cli_zsh_autocomplete() {
local -a opts
local cur
cur=${words[-1]}
if [[ "$cur" == "-"* ]]; then
opts=("${(@f)$(${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
else
opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-bash-completion)}")
fi
if [[ "${opts[1]}" != "" ]]; then
_describe 'values' opts
else
_files
fi
}
compdef _cli_zsh_autocomplete $PROG

View File

@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
@ -39,42 +39,44 @@ var (
gitDate = "" gitDate = ""
app *cli.App app *cli.App
)
var (
// Flags needed by abigen // Flags needed by abigen
abiFlag = cli.StringFlag{ abiFlag = &cli.StringFlag{
Name: "abi", Name: "abi",
Usage: "Path to the Ethereum contract ABI json to bind, - for STDIN", Usage: "Path to the Ethereum contract ABI json to bind, - for STDIN",
} }
binFlag = cli.StringFlag{ binFlag = &cli.StringFlag{
Name: "bin", Name: "bin",
Usage: "Path to the Ethereum contract bytecode (generate deploy method)", Usage: "Path to the Ethereum contract bytecode (generate deploy method)",
} }
typeFlag = cli.StringFlag{ typeFlag = &cli.StringFlag{
Name: "type", Name: "type",
Usage: "Struct name for the binding (default = package name)", Usage: "Struct name for the binding (default = package name)",
} }
jsonFlag = cli.StringFlag{ jsonFlag = &cli.StringFlag{
Name: "combined-json", Name: "combined-json",
Usage: "Path to the combined-json file generated by compiler, - for STDIN", Usage: "Path to the combined-json file generated by compiler, - for STDIN",
} }
excFlag = cli.StringFlag{ excFlag = &cli.StringFlag{
Name: "exc", Name: "exc",
Usage: "Comma separated types to exclude from binding", Usage: "Comma separated types to exclude from binding",
} }
pkgFlag = cli.StringFlag{ pkgFlag = &cli.StringFlag{
Name: "pkg", Name: "pkg",
Usage: "Package name to generate the binding into", Usage: "Package name to generate the binding into",
} }
outFlag = cli.StringFlag{ outFlag = &cli.StringFlag{
Name: "out", Name: "out",
Usage: "Output file for the generated binding (default = stdout)", Usage: "Output file for the generated binding (default = stdout)",
} }
langFlag = cli.StringFlag{ langFlag = &cli.StringFlag{
Name: "lang", Name: "lang",
Usage: "Destination language for the bindings (go, java, objc)", Usage: "Destination language for the bindings (go, java, objc)",
Value: "go", Value: "go",
} }
aliasFlag = cli.StringFlag{ aliasFlag = &cli.StringFlag{
Name: "alias", Name: "alias",
Usage: "Comma separated aliases for function and event renaming, e.g. original1=alias1, original2=alias2", Usage: "Comma separated aliases for function and event renaming, e.g. original1=alias1, original2=alias2",
} }
@ -82,6 +84,7 @@ var (
func init() { func init() {
app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool")
app.Name = "abigen"
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
abiFlag, abiFlag,
binFlag, binFlag,
@ -93,17 +96,17 @@ func init() {
langFlag, langFlag,
aliasFlag, aliasFlag,
} }
app.Action = utils.MigrateFlags(abigen) app.Action = abigen
cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate
} }
func abigen(c *cli.Context) error { func abigen(c *cli.Context) error {
utils.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected. utils.CheckExclusive(c, abiFlag, jsonFlag) // Only one source can be selected.
if c.GlobalString(pkgFlag.Name) == "" {
if c.String(pkgFlag.Name) == "" {
utils.Fatalf("No destination package specified (--pkg)") utils.Fatalf("No destination package specified (--pkg)")
} }
var lang bind.Lang var lang bind.Lang
switch c.GlobalString(langFlag.Name) { switch c.String(langFlag.Name) {
case "go": case "go":
lang = bind.LangGo lang = bind.LangGo
case "java": case "java":
@ -112,7 +115,7 @@ func abigen(c *cli.Context) error {
lang = bind.LangObjC lang = bind.LangObjC
utils.Fatalf("Objc binding generation is uncompleted") utils.Fatalf("Objc binding generation is uncompleted")
default: default:
utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.GlobalString(langFlag.Name)) utils.Fatalf("Unsupported destination language \"%s\" (--lang)", c.String(langFlag.Name))
} }
// If the entire solidity code was specified, build and bind based on that // If the entire solidity code was specified, build and bind based on that
var ( var (
@ -123,13 +126,13 @@ func abigen(c *cli.Context) error {
libs = make(map[string]string) libs = make(map[string]string)
aliases = make(map[string]string) aliases = make(map[string]string)
) )
if c.GlobalString(abiFlag.Name) != "" { if c.String(abiFlag.Name) != "" {
// Load up the ABI, optional bytecode and type name from the parameters // Load up the ABI, optional bytecode and type name from the parameters
var ( var (
abi []byte abi []byte
err error err error
) )
input := c.GlobalString(abiFlag.Name) input := c.String(abiFlag.Name)
if input == "-" { if input == "-" {
abi, err = io.ReadAll(os.Stdin) abi, err = io.ReadAll(os.Stdin)
} else { } else {
@ -141,7 +144,7 @@ func abigen(c *cli.Context) error {
abis = append(abis, string(abi)) abis = append(abis, string(abi))
var bin []byte var bin []byte
if binFile := c.GlobalString(binFlag.Name); binFile != "" { if binFile := c.String(binFlag.Name); binFile != "" {
if bin, err = os.ReadFile(binFile); err != nil { if bin, err = os.ReadFile(binFile); err != nil {
utils.Fatalf("Failed to read input bytecode: %v", err) utils.Fatalf("Failed to read input bytecode: %v", err)
} }
@ -151,22 +154,22 @@ func abigen(c *cli.Context) error {
} }
bins = append(bins, string(bin)) bins = append(bins, string(bin))
kind := c.GlobalString(typeFlag.Name) kind := c.String(typeFlag.Name)
if kind == "" { if kind == "" {
kind = c.GlobalString(pkgFlag.Name) kind = c.String(pkgFlag.Name)
} }
types = append(types, kind) types = append(types, kind)
} else { } else {
// Generate the list of types to exclude from binding // Generate the list of types to exclude from binding
exclude := make(map[string]bool) exclude := make(map[string]bool)
for _, kind := range strings.Split(c.GlobalString(excFlag.Name), ",") { for _, kind := range strings.Split(c.String(excFlag.Name), ",") {
exclude[strings.ToLower(kind)] = true exclude[strings.ToLower(kind)] = true
} }
var contracts map[string]*compiler.Contract var contracts map[string]*compiler.Contract
if c.GlobalIsSet(jsonFlag.Name) { if c.IsSet(jsonFlag.Name) {
var ( var (
input = c.GlobalString(jsonFlag.Name) input = c.String(jsonFlag.Name)
jsonOutput []byte jsonOutput []byte
err error err error
) )
@ -207,28 +210,28 @@ func abigen(c *cli.Context) error {
} }
} }
// Extract all aliases from the flags // Extract all aliases from the flags
if c.GlobalIsSet(aliasFlag.Name) { if c.IsSet(aliasFlag.Name) {
// We support multi-versions for aliasing // We support multi-versions for aliasing
// e.g. // e.g.
// foo=bar,foo2=bar2 // foo=bar,foo2=bar2
// foo:bar,foo2:bar2 // foo:bar,foo2:bar2
re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`) re := regexp.MustCompile(`(?:(\w+)[:=](\w+))`)
submatches := re.FindAllStringSubmatch(c.GlobalString(aliasFlag.Name), -1) submatches := re.FindAllStringSubmatch(c.String(aliasFlag.Name), -1)
for _, match := range submatches { for _, match := range submatches {
aliases[match[1]] = match[2] aliases[match[1]] = match[2]
} }
} }
// Generate the contract binding // Generate the contract binding
code, err := bind.Bind(types, abis, bins, sigs, c.GlobalString(pkgFlag.Name), lang, libs, aliases) code, err := bind.Bind(types, abis, bins, sigs, c.String(pkgFlag.Name), lang, libs, aliases)
if err != nil { if err != nil {
utils.Fatalf("Failed to generate ABI binding: %v", err) utils.Fatalf("Failed to generate ABI binding: %v", err)
} }
// Either flush it out to a file or display on the standard output // Either flush it out to a file or display on the standard output
if !c.GlobalIsSet(outFlag.Name) { if !c.IsSet(outFlag.Name) {
fmt.Printf("%s\n", code) fmt.Printf("%s\n", code)
return nil return nil
} }
if err := os.WriteFile(c.GlobalString(outFlag.Name), []byte(code), 0600); err != nil { if err := os.WriteFile(c.String(outFlag.Name), []byte(code), 0600); err != nil {
utils.Fatalf("Failed to write ABI binding: %v", err) utils.Fatalf("Failed to write ABI binding: %v", err)
} }
return nil return nil

View File

@ -28,12 +28,12 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
// newClient creates a client with specified remote URL. // newClient creates a client with specified remote URL.
func newClient(ctx *cli.Context) *ethclient.Client { func newClient(ctx *cli.Context) *ethclient.Client {
client, err := ethclient.Dial(ctx.GlobalString(nodeURLFlag.Name)) client, err := ethclient.Dial(ctx.String(nodeURLFlag.Name))
if err != nil { if err != nil {
utils.Fatalf("Failed to connect to Ethereum node: %v", err) utils.Fatalf("Failed to connect to Ethereum node: %v", err)
} }
@ -64,9 +64,9 @@ func getContractAddr(client *rpc.Client) common.Address {
func getCheckpoint(ctx *cli.Context, client *rpc.Client) *params.TrustedCheckpoint { func getCheckpoint(ctx *cli.Context, client *rpc.Client) *params.TrustedCheckpoint {
var checkpoint *params.TrustedCheckpoint var checkpoint *params.TrustedCheckpoint
if ctx.GlobalIsSet(indexFlag.Name) { if ctx.IsSet(indexFlag.Name) {
var result [3]string var result [3]string
index := uint64(ctx.GlobalInt64(indexFlag.Name)) index := uint64(ctx.Int64(indexFlag.Name))
if err := client.Call(&result, "les_getCheckpoint", index); err != nil { if err := client.Call(&result, "les_getCheckpoint", index); err != nil {
utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err) utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err)
} }

View File

@ -36,10 +36,10 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var commandDeploy = cli.Command{ var commandDeploy = &cli.Command{
Name: "deploy", Name: "deploy",
Usage: "Deploy a new checkpoint oracle contract", Usage: "Deploy a new checkpoint oracle contract",
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -49,10 +49,10 @@ var commandDeploy = cli.Command{
signersFlag, signersFlag,
thresholdFlag, thresholdFlag,
}, },
Action: utils.MigrateFlags(deploy), Action: deploy,
} }
var commandSign = cli.Command{ var commandSign = &cli.Command{
Name: "sign", Name: "sign",
Usage: "Sign the checkpoint with the specified key", Usage: "Sign the checkpoint with the specified key",
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -63,10 +63,10 @@ var commandSign = cli.Command{
hashFlag, hashFlag,
oracleFlag, oracleFlag,
}, },
Action: utils.MigrateFlags(sign), Action: sign,
} }
var commandPublish = cli.Command{ var commandPublish = &cli.Command{
Name: "publish", Name: "publish",
Usage: "Publish a checkpoint into the oracle", Usage: "Publish a checkpoint into the oracle",
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -76,7 +76,7 @@ var commandPublish = cli.Command{
indexFlag, indexFlag,
signaturesFlag, signaturesFlag,
}, },
Action: utils.MigrateFlags(publish), Action: publish,
} }
// deploy deploys the checkpoint registrar contract. // deploy deploys the checkpoint registrar contract.
@ -132,7 +132,7 @@ func sign(ctx *cli.Context) error {
node *rpc.Client node *rpc.Client
oracle *checkpointoracle.CheckpointOracle oracle *checkpointoracle.CheckpointOracle
) )
if !ctx.GlobalIsSet(nodeURLFlag.Name) { if !ctx.IsSet(nodeURLFlag.Name) {
// Offline mode signing // Offline mode signing
offline = true offline = true
if !ctx.IsSet(hashFlag.Name) { if !ctx.IsSet(hashFlag.Name) {
@ -151,7 +151,7 @@ func sign(ctx *cli.Context) error {
address = common.HexToAddress(ctx.String(oracleFlag.Name)) address = common.HexToAddress(ctx.String(oracleFlag.Name))
} else { } else {
// Interactive mode signing, retrieve the data from the remote node // Interactive mode signing, retrieve the data from the remote node
node = newRPCClient(ctx.GlobalString(nodeURLFlag.Name)) node = newRPCClient(ctx.String(nodeURLFlag.Name))
checkpoint := getCheckpoint(ctx, node) checkpoint := getCheckpoint(ctx, node)
chash, cindex, address = checkpoint.Hash(), checkpoint.SectionIndex, getContractAddr(node) chash, cindex, address = checkpoint.Hash(), checkpoint.SectionIndex, getContractAddr(node)
@ -265,7 +265,7 @@ func publish(ctx *cli.Context) error {
} }
// Retrieve the checkpoint we want to sign to sort the signatures // Retrieve the checkpoint we want to sign to sort the signatures
var ( var (
client = newRPCClient(ctx.GlobalString(nodeURLFlag.Name)) client = newRPCClient(ctx.String(nodeURLFlag.Name))
addr, oracle = newContract(client) addr, oracle = newContract(client)
checkpoint = getCheckpoint(ctx, client) checkpoint = getCheckpoint(ctx, client)
sighash = sighash(checkpoint.SectionIndex, addr, checkpoint.Hash()) sighash = sighash(checkpoint.SectionIndex, addr, checkpoint.Hash())

View File

@ -25,20 +25,20 @@ import (
"github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
// Git SHA1 commit hash of the release (set via linker flags) // Git SHA1 commit hash of the release (set via linker flags)
gitCommit = "" gitCommit = ""
gitDate = "" gitDate = ""
)
var app *cli.App app *cli.App
)
func init() { func init() {
app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool")
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
commandStatus, commandStatus,
commandDeploy, commandDeploy,
commandSign, commandSign,
@ -48,46 +48,45 @@ func init() {
oracleFlag, oracleFlag,
nodeURLFlag, nodeURLFlag,
} }
cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate
} }
// Commonly used command line flags. // Commonly used command line flags.
var ( var (
indexFlag = cli.Int64Flag{ indexFlag = &cli.Int64Flag{
Name: "index", Name: "index",
Usage: "Checkpoint index (query latest from remote node if not specified)", Usage: "Checkpoint index (query latest from remote node if not specified)",
} }
hashFlag = cli.StringFlag{ hashFlag = &cli.StringFlag{
Name: "hash", Name: "hash",
Usage: "Checkpoint hash (query latest from remote node if not specified)", Usage: "Checkpoint hash (query latest from remote node if not specified)",
} }
oracleFlag = cli.StringFlag{ oracleFlag = &cli.StringFlag{
Name: "oracle", Name: "oracle",
Usage: "Checkpoint oracle address (query from remote node if not specified)", Usage: "Checkpoint oracle address (query from remote node if not specified)",
} }
thresholdFlag = cli.Int64Flag{ thresholdFlag = &cli.Int64Flag{
Name: "threshold", Name: "threshold",
Usage: "Minimal number of signatures required to approve a checkpoint", Usage: "Minimal number of signatures required to approve a checkpoint",
} }
nodeURLFlag = cli.StringFlag{ nodeURLFlag = &cli.StringFlag{
Name: "rpc", Name: "rpc",
Value: "http://localhost:8545", Value: "http://localhost:8545",
Usage: "The rpc endpoint of a local or remote geth node", Usage: "The rpc endpoint of a local or remote geth node",
} }
clefURLFlag = cli.StringFlag{ clefURLFlag = &cli.StringFlag{
Name: "clef", Name: "clef",
Value: "http://localhost:8550", Value: "http://localhost:8550",
Usage: "The rpc endpoint of clef", Usage: "The rpc endpoint of clef",
} }
signerFlag = cli.StringFlag{ signerFlag = &cli.StringFlag{
Name: "signer", Name: "signer",
Usage: "Signer address for clef signing", Usage: "Signer address for clef signing",
} }
signersFlag = cli.StringFlag{ signersFlag = &cli.StringFlag{
Name: "signers", Name: "signers",
Usage: "Comma separated accounts of trusted checkpoint signers", Usage: "Comma separated accounts of trusted checkpoint signers",
} }
signaturesFlag = cli.StringFlag{ signaturesFlag = &cli.StringFlag{
Name: "signatures", Name: "signatures",
Usage: "Comma separated checkpoint signatures to submit", Usage: "Comma separated checkpoint signatures to submit",
} }

View File

@ -19,24 +19,23 @@ package main
import ( import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var commandStatus = cli.Command{ var commandStatus = &cli.Command{
Name: "status", Name: "status",
Usage: "Fetches the signers and checkpoint status of the oracle contract", Usage: "Fetches the signers and checkpoint status of the oracle contract",
Flags: []cli.Flag{ Flags: []cli.Flag{
nodeURLFlag, nodeURLFlag,
}, },
Action: utils.MigrateFlags(status), Action: status,
} }
// status fetches the admin list of specified registrar contract. // status fetches the admin list of specified registrar contract.
func status(ctx *cli.Context) error { func status(ctx *cli.Context) error {
// Create a wrapper around the checkpoint oracle contract // Create a wrapper around the checkpoint oracle contract
addr, oracle := newContract(newRPCClient(ctx.GlobalString(nodeURLFlag.Name))) addr, oracle := newContract(newRPCClient(ctx.String(nodeURLFlag.Name)))
fmt.Printf("Oracle => %s\n", addr.Hex()) fmt.Printf("Oracle => %s\n", addr.Hex())
fmt.Println() fmt.Println()

View File

@ -30,7 +30,6 @@ import (
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"runtime" "runtime"
"sort"
"strings" "strings"
"time" "time"
@ -55,7 +54,7 @@ import (
"github.com/ethereum/go-ethereum/signer/storage" "github.com/ethereum/go-ethereum/signer/storage"
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
const legalWarning = ` const legalWarning = `
@ -73,70 +72,70 @@ PURPOSE. See the GNU General Public License for more details.
` `
var ( var (
logLevelFlag = cli.IntFlag{ logLevelFlag = &cli.IntFlag{
Name: "loglevel", Name: "loglevel",
Value: 4, Value: 4,
Usage: "log level to emit to the screen", Usage: "log level to emit to the screen",
} }
advancedMode = cli.BoolFlag{ advancedMode = &cli.BoolFlag{
Name: "advanced", Name: "advanced",
Usage: "If enabled, issues warnings instead of rejections for suspicious requests. Default off", Usage: "If enabled, issues warnings instead of rejections for suspicious requests. Default off",
} }
acceptFlag = cli.BoolFlag{ acceptFlag = &cli.BoolFlag{
Name: "suppress-bootwarn", Name: "suppress-bootwarn",
Usage: "If set, does not show the warning during boot", Usage: "If set, does not show the warning during boot",
} }
keystoreFlag = cli.StringFlag{ keystoreFlag = &cli.StringFlag{
Name: "keystore", Name: "keystore",
Value: filepath.Join(node.DefaultDataDir(), "keystore"), Value: filepath.Join(node.DefaultDataDir(), "keystore"),
Usage: "Directory for the keystore", Usage: "Directory for the keystore",
} }
configdirFlag = cli.StringFlag{ configdirFlag = &cli.StringFlag{
Name: "configdir", Name: "configdir",
Value: DefaultConfigDir(), Value: DefaultConfigDir(),
Usage: "Directory for Clef configuration", Usage: "Directory for Clef configuration",
} }
chainIdFlag = cli.Int64Flag{ chainIdFlag = &cli.Int64Flag{
Name: "chainid", Name: "chainid",
Value: params.MainnetChainConfig.ChainID.Int64(), Value: params.MainnetChainConfig.ChainID.Int64(),
Usage: "Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli)", Usage: "Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli)",
} }
rpcPortFlag = cli.IntFlag{ rpcPortFlag = &cli.IntFlag{
Name: "http.port", Name: "http.port",
Usage: "HTTP-RPC server listening port", Usage: "HTTP-RPC server listening port",
Value: node.DefaultHTTPPort + 5, Value: node.DefaultHTTPPort + 5,
Category: flags.APICategory,
} }
signerSecretFlag = cli.StringFlag{ signerSecretFlag = &cli.StringFlag{
Name: "signersecret", Name: "signersecret",
Usage: "A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash", Usage: "A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash",
} }
customDBFlag = cli.StringFlag{ customDBFlag = &cli.StringFlag{
Name: "4bytedb-custom", Name: "4bytedb-custom",
Usage: "File used for writing new 4byte-identifiers submitted via API", Usage: "File used for writing new 4byte-identifiers submitted via API",
Value: "./4byte-custom.json", Value: "./4byte-custom.json",
} }
auditLogFlag = cli.StringFlag{ auditLogFlag = &cli.StringFlag{
Name: "auditlog", Name: "auditlog",
Usage: "File used to emit audit logs. Set to \"\" to disable", Usage: "File used to emit audit logs. Set to \"\" to disable",
Value: "audit.log", Value: "audit.log",
} }
ruleFlag = cli.StringFlag{ ruleFlag = &cli.StringFlag{
Name: "rules", Name: "rules",
Usage: "Path to the rule file to auto-authorize requests with", Usage: "Path to the rule file to auto-authorize requests with",
} }
stdiouiFlag = cli.BoolFlag{ stdiouiFlag = &cli.BoolFlag{
Name: "stdio-ui", Name: "stdio-ui",
Usage: "Use STDIN/STDOUT as a channel for an external UI. " + Usage: "Use STDIN/STDOUT as a channel for an external UI. " +
"This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user " + "This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user " +
"interface, and can be used when Clef is started by an external process.", "interface, and can be used when Clef is started by an external process.",
} }
testFlag = cli.BoolFlag{ testFlag = &cli.BoolFlag{
Name: "stdio-ui-test", Name: "stdio-ui-test",
Usage: "Mechanism to test interface between Clef and UI. Requires 'stdio-ui'.", Usage: "Mechanism to test interface between Clef and UI. Requires 'stdio-ui'.",
} }
app = cli.NewApp() initCommand = &cli.Command{
initCommand = cli.Command{ Action: initializeSecrets,
Action: utils.MigrateFlags(initializeSecrets),
Name: "init", Name: "init",
Usage: "Initialize the signer, generate secret storage", Usage: "Initialize the signer, generate secret storage",
ArgsUsage: "", ArgsUsage: "",
@ -148,8 +147,8 @@ var (
The init command generates a master seed which Clef can use to store credentials and data needed for The init command generates a master seed which Clef can use to store credentials and data needed for
the rule-engine to work.`, the rule-engine to work.`,
} }
attestCommand = cli.Command{ attestCommand = &cli.Command{
Action: utils.MigrateFlags(attestFile), Action: attestFile,
Name: "attest", Name: "attest",
Usage: "Attest that a js-file is to be used", Usage: "Attest that a js-file is to be used",
ArgsUsage: "<sha256sum>", ArgsUsage: "<sha256sum>",
@ -165,8 +164,8 @@ incoming requests.
Whenever you make an edit to the rule file, you need to use attestation to tell Whenever you make an edit to the rule file, you need to use attestation to tell
Clef that the file is 'safe' to execute.`, Clef that the file is 'safe' to execute.`,
} }
setCredentialCommand = cli.Command{ setCredentialCommand = &cli.Command{
Action: utils.MigrateFlags(setCredential), Action: setCredential,
Name: "setpw", Name: "setpw",
Usage: "Store a credential for a keystore file", Usage: "Store a credential for a keystore file",
ArgsUsage: "<address>", ArgsUsage: "<address>",
@ -178,8 +177,8 @@ Clef that the file is 'safe' to execute.`,
Description: ` Description: `
The setpw command stores a password for a given address (keyfile). The setpw command stores a password for a given address (keyfile).
`} `}
delCredentialCommand = cli.Command{ delCredentialCommand = &cli.Command{
Action: utils.MigrateFlags(removeCredential), Action: removeCredential,
Name: "delpw", Name: "delpw",
Usage: "Remove a credential for a keystore file", Usage: "Remove a credential for a keystore file",
ArgsUsage: "<address>", ArgsUsage: "<address>",
@ -191,8 +190,8 @@ The setpw command stores a password for a given address (keyfile).
Description: ` Description: `
The delpw command removes a password for a given address (keyfile). The delpw command removes a password for a given address (keyfile).
`} `}
newAccountCommand = cli.Command{ newAccountCommand = &cli.Command{
Action: utils.MigrateFlags(newAccount), Action: newAccount,
Name: "newaccount", Name: "newaccount",
Usage: "Create a new account", Usage: "Create a new account",
ArgsUsage: "", ArgsUsage: "",
@ -207,7 +206,7 @@ The newaccount command creates a new keystore-backed account. It is a convenienc
which can be used in lieu of an external UI.`, which can be used in lieu of an external UI.`,
} }
gendocCommand = cli.Command{ gendocCommand = &cli.Command{
Action: GenDoc, Action: GenDoc,
Name: "gendoc", Name: "gendoc",
Usage: "Generate documentation about json-rpc format", Usage: "Generate documentation about json-rpc format",
@ -216,39 +215,16 @@ The gendoc generates example structures of the json-rpc communication types.
`} `}
) )
// AppHelpFlagGroups is the application flags, grouped by functionality. var (
var AppHelpFlagGroups = []flags.FlagGroup{ // Git SHA1 commit hash of the release (set via linker flags)
{ gitCommit = ""
Name: "FLAGS", gitDate = ""
Flags: []cli.Flag{
logLevelFlag, app = flags.NewApp(gitCommit, gitDate, "Manage Ethereum account operations")
keystoreFlag, )
configdirFlag,
chainIdFlag,
utils.LightKDFFlag,
utils.NoUSBFlag,
utils.SmartCardDaemonPathFlag,
utils.HTTPListenAddrFlag,
utils.HTTPVirtualHostsFlag,
utils.IPCDisabledFlag,
utils.IPCPathFlag,
utils.HTTPEnabledFlag,
rpcPortFlag,
signerSecretFlag,
customDBFlag,
auditLogFlag,
ruleFlag,
stdiouiFlag,
testFlag,
advancedMode,
acceptFlag,
},
},
}
func init() { func init() {
app.Name = "Clef" app.Name = "Clef"
app.Usage = "Manage Ethereum account operations"
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
logLevelFlag, logLevelFlag,
keystoreFlag, keystoreFlag,
@ -273,46 +249,12 @@ func init() {
acceptFlag, acceptFlag,
} }
app.Action = signer app.Action = signer
app.Commands = []cli.Command{initCommand, app.Commands = []*cli.Command{initCommand,
attestCommand, attestCommand,
setCredentialCommand, setCredentialCommand,
delCredentialCommand, delCredentialCommand,
newAccountCommand, newAccountCommand,
gendocCommand} gendocCommand,
cli.CommandHelpTemplate = flags.CommandHelpTemplate
// Override the default app help template
cli.AppHelpTemplate = flags.ClefAppHelpTemplate
// 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 == flags.ClefAppHelpTemplate {
// Render out custom usage screen
originalHelpPrinter(w, tmpl, flags.HelpData{App: data, FlagGroups: AppHelpFlagGroups})
} else if tmpl == flags.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[flags.FlagCategory(flag, AppHelpFlagGroups)] = append(categorized[flags.FlagCategory(flag, AppHelpFlagGroups)], flag)
}
}
// sort to get a stable ordering
sorted := make([]flags.FlagGroup, 0, len(categorized))
for cat, flgs := range categorized {
sorted = append(sorted, flags.FlagGroup{Name: cat, Flags: flgs})
}
sort.Sort(flags.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)
}
} }
} }
@ -329,7 +271,7 @@ func initializeSecrets(c *cli.Context) error {
return err return err
} }
// Ensure the master key does not yet exist, we're not willing to overwrite // Ensure the master key does not yet exist, we're not willing to overwrite
configDir := c.GlobalString(configdirFlag.Name) configDir := c.String(configdirFlag.Name)
if err := os.Mkdir(configDir, 0700); err != nil && !os.IsExist(err) { if err := os.Mkdir(configDir, 0700); err != nil && !os.IsExist(err) {
return err return err
} }
@ -347,7 +289,7 @@ func initializeSecrets(c *cli.Context) error {
return fmt.Errorf("failed to read enough random") return fmt.Errorf("failed to read enough random")
} }
n, p := keystore.StandardScryptN, keystore.StandardScryptP n, p := keystore.StandardScryptN, keystore.StandardScryptP
if c.GlobalBool(utils.LightKDFFlag.Name) { if c.Bool(utils.LightKDFFlag.Name) {
n, p = keystore.LightScryptN, keystore.LightScryptP n, p = keystore.LightScryptN, keystore.LightScryptP
} }
text := "The master seed of clef will be locked with a password.\nPlease specify a password. Do not forget this password!" text := "The master seed of clef will be locked with a password.\nPlease specify a password. Do not forget this password!"
@ -390,8 +332,9 @@ You should treat 'masterseed.json' with utmost secrecy and make a backup of it!
`) `)
return nil return nil
} }
func attestFile(ctx *cli.Context) error { func attestFile(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.NArg() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
if err := initialize(ctx); err != nil { if err := initialize(ctx); err != nil {
@ -402,7 +345,7 @@ func attestFile(ctx *cli.Context) error {
if err != nil { if err != nil {
utils.Fatalf(err.Error()) utils.Fatalf(err.Error())
} }
configDir := ctx.GlobalString(configdirFlag.Name) configDir := ctx.String(configdirFlag.Name)
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
confKey := crypto.Keccak256([]byte("config"), stretchedKey) confKey := crypto.Keccak256([]byte("config"), stretchedKey)
@ -415,7 +358,7 @@ func attestFile(ctx *cli.Context) error {
} }
func setCredential(ctx *cli.Context) error { func setCredential(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.NArg() < 1 {
utils.Fatalf("This command requires an address to be passed as an argument") utils.Fatalf("This command requires an address to be passed as an argument")
} }
if err := initialize(ctx); err != nil { if err := initialize(ctx); err != nil {
@ -433,7 +376,7 @@ func setCredential(ctx *cli.Context) error {
if err != nil { if err != nil {
utils.Fatalf(err.Error()) utils.Fatalf(err.Error())
} }
configDir := ctx.GlobalString(configdirFlag.Name) configDir := ctx.String(configdirFlag.Name)
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey) pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey)
@ -445,7 +388,7 @@ func setCredential(ctx *cli.Context) error {
} }
func removeCredential(ctx *cli.Context) error { func removeCredential(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.NArg() < 1 {
utils.Fatalf("This command requires an address to be passed as an argument") utils.Fatalf("This command requires an address to be passed as an argument")
} }
if err := initialize(ctx); err != nil { if err := initialize(ctx); err != nil {
@ -461,7 +404,7 @@ func removeCredential(ctx *cli.Context) error {
if err != nil { if err != nil {
utils.Fatalf(err.Error()) utils.Fatalf(err.Error())
} }
configDir := ctx.GlobalString(configdirFlag.Name) configDir := ctx.String(configdirFlag.Name)
vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10])) vaultLocation := filepath.Join(configDir, common.Bytes2Hex(crypto.Keccak256([]byte("vault"), stretchedKey)[:10]))
pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey) pwkey := crypto.Keccak256([]byte("credentials"), stretchedKey)
@ -481,8 +424,8 @@ func newAccount(c *cli.Context) error {
var ( var (
ui = core.NewCommandlineUI() ui = core.NewCommandlineUI()
pwStorage storage.Storage = &storage.NoStorage{} pwStorage storage.Storage = &storage.NoStorage{}
ksLoc = c.GlobalString(keystoreFlag.Name) ksLoc = c.String(keystoreFlag.Name)
lightKdf = c.GlobalBool(utils.LightKDFFlag.Name) lightKdf = c.Bool(utils.LightKDFFlag.Name)
) )
log.Info("Starting clef", "keystore", ksLoc, "light-kdf", lightKdf) log.Info("Starting clef", "keystore", ksLoc, "light-kdf", lightKdf)
am := core.StartClefAccountManager(ksLoc, true, lightKdf, "") am := core.StartClefAccountManager(ksLoc, true, lightKdf, "")
@ -500,13 +443,13 @@ func newAccount(c *cli.Context) error {
func initialize(c *cli.Context) error { func initialize(c *cli.Context) error {
// Set up the logger to print everything // Set up the logger to print everything
logOutput := os.Stdout logOutput := os.Stdout
if c.GlobalBool(stdiouiFlag.Name) { if c.Bool(stdiouiFlag.Name) {
logOutput = os.Stderr logOutput = os.Stderr
// If using the stdioui, we can't do the 'confirm'-flow // If using the stdioui, we can't do the 'confirm'-flow
if !c.GlobalBool(acceptFlag.Name) { if !c.Bool(acceptFlag.Name) {
fmt.Fprint(logOutput, legalWarning) fmt.Fprint(logOutput, legalWarning)
} }
} else if !c.GlobalBool(acceptFlag.Name) { } else if !c.Bool(acceptFlag.Name) {
if !confirm(legalWarning) { if !confirm(legalWarning) {
return fmt.Errorf("aborted by user") return fmt.Errorf("aborted by user")
} }
@ -545,8 +488,8 @@ func ipcEndpoint(ipcPath, datadir string) string {
func signer(c *cli.Context) error { func signer(c *cli.Context) error {
// If we have some unrecognized command, bail out // If we have some unrecognized command, bail out
if args := c.Args(); len(args) > 0 { if c.NArg() > 0 {
return fmt.Errorf("invalid command: %q", args[0]) return fmt.Errorf("invalid command: %q", c.Args().First())
} }
if err := initialize(c); err != nil { if err := initialize(c); err != nil {
return err return err
@ -554,7 +497,7 @@ func signer(c *cli.Context) error {
var ( var (
ui core.UIClientAPI ui core.UIClientAPI
) )
if c.GlobalBool(stdiouiFlag.Name) { if c.Bool(stdiouiFlag.Name) {
log.Info("Using stdin/stdout as UI-channel") log.Info("Using stdin/stdout as UI-channel")
ui = core.NewStdIOUI() ui = core.NewStdIOUI()
} else { } else {
@ -562,7 +505,7 @@ func signer(c *cli.Context) error {
ui = core.NewCommandlineUI() ui = core.NewCommandlineUI()
} }
// 4bytedb data // 4bytedb data
fourByteLocal := c.GlobalString(customDBFlag.Name) fourByteLocal := c.String(customDBFlag.Name)
db, err := fourbyte.NewWithFile(fourByteLocal) db, err := fourbyte.NewWithFile(fourByteLocal)
if err != nil { if err != nil {
utils.Fatalf(err.Error()) utils.Fatalf(err.Error())
@ -574,7 +517,7 @@ func signer(c *cli.Context) error {
api core.ExternalAPI api core.ExternalAPI
pwStorage storage.Storage = &storage.NoStorage{} pwStorage storage.Storage = &storage.NoStorage{}
) )
configDir := c.GlobalString(configdirFlag.Name) configDir := c.String(configdirFlag.Name)
if stretchedKey, err := readMasterKey(c, ui); err != nil { if stretchedKey, err := readMasterKey(c, ui); err != nil {
log.Warn("Failed to open master, rules disabled", "err", err) log.Warn("Failed to open master, rules disabled", "err", err)
} else { } else {
@ -591,7 +534,7 @@ func signer(c *cli.Context) error {
configStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "config.json"), confkey) configStorage := storage.NewAESEncryptedStorage(filepath.Join(vaultLocation, "config.json"), confkey)
// Do we have a rule-file? // Do we have a rule-file?
if ruleFile := c.GlobalString(ruleFlag.Name); ruleFile != "" { if ruleFile := c.String(ruleFlag.Name); ruleFile != "" {
ruleJS, err := os.ReadFile(ruleFile) ruleJS, err := os.ReadFile(ruleFile)
if err != nil { if err != nil {
log.Warn("Could not load rules, disabling", "file", ruleFile, "err", err) log.Warn("Could not load rules, disabling", "file", ruleFile, "err", err)
@ -615,12 +558,12 @@ func signer(c *cli.Context) error {
} }
} }
var ( var (
chainId = c.GlobalInt64(chainIdFlag.Name) chainId = c.Int64(chainIdFlag.Name)
ksLoc = c.GlobalString(keystoreFlag.Name) ksLoc = c.String(keystoreFlag.Name)
lightKdf = c.GlobalBool(utils.LightKDFFlag.Name) lightKdf = c.Bool(utils.LightKDFFlag.Name)
advanced = c.GlobalBool(advancedMode.Name) advanced = c.Bool(advancedMode.Name)
nousb = c.GlobalBool(utils.NoUSBFlag.Name) nousb = c.Bool(utils.NoUSBFlag.Name)
scpath = c.GlobalString(utils.SmartCardDaemonPathFlag.Name) scpath = c.String(utils.SmartCardDaemonPathFlag.Name)
) )
log.Info("Starting signer", "chainid", chainId, "keystore", ksLoc, log.Info("Starting signer", "chainid", chainId, "keystore", ksLoc,
"light-kdf", lightKdf, "advanced", advanced) "light-kdf", lightKdf, "advanced", advanced)
@ -632,7 +575,7 @@ func signer(c *cli.Context) error {
ui.RegisterUIServer(core.NewUIServerAPI(apiImpl)) ui.RegisterUIServer(core.NewUIServerAPI(apiImpl))
api = apiImpl api = apiImpl
// Audit logging // Audit logging
if logfile := c.GlobalString(auditLogFlag.Name); logfile != "" { if logfile := c.String(auditLogFlag.Name); logfile != "" {
api, err = core.NewAuditLogger(logfile, api) api, err = core.NewAuditLogger(logfile, api)
if err != nil { if err != nil {
utils.Fatalf(err.Error()) utils.Fatalf(err.Error())
@ -650,9 +593,9 @@ func signer(c *cli.Context) error {
Service: api, Service: api,
Version: "1.0"}, Version: "1.0"},
} }
if c.GlobalBool(utils.HTTPEnabledFlag.Name) { if c.Bool(utils.HTTPEnabledFlag.Name) {
vhosts := utils.SplitAndTrim(c.GlobalString(utils.HTTPVirtualHostsFlag.Name)) vhosts := utils.SplitAndTrim(c.String(utils.HTTPVirtualHostsFlag.Name))
cors := utils.SplitAndTrim(c.GlobalString(utils.HTTPCORSDomainFlag.Name)) cors := utils.SplitAndTrim(c.String(utils.HTTPCORSDomainFlag.Name))
srv := rpc.NewServer() srv := rpc.NewServer()
err := node.RegisterApis(rpcAPI, []string{"account"}, srv) err := node.RegisterApis(rpcAPI, []string{"account"}, srv)
@ -665,7 +608,7 @@ func signer(c *cli.Context) error {
port := c.Int(rpcPortFlag.Name) port := c.Int(rpcPortFlag.Name)
// start http server // start http server
httpEndpoint := fmt.Sprintf("%s:%d", c.GlobalString(utils.HTTPListenAddrFlag.Name), port) httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.HTTPListenAddrFlag.Name), port)
httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler) httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler)
if err != nil { if err != nil {
utils.Fatalf("Could not start RPC api: %v", err) utils.Fatalf("Could not start RPC api: %v", err)
@ -679,8 +622,8 @@ func signer(c *cli.Context) error {
log.Info("HTTP endpoint closed", "url", extapiURL) log.Info("HTTP endpoint closed", "url", extapiURL)
}() }()
} }
if !c.GlobalBool(utils.IPCDisabledFlag.Name) { if !c.Bool(utils.IPCDisabledFlag.Name) {
givenPath := c.GlobalString(utils.IPCPathFlag.Name) givenPath := c.String(utils.IPCPathFlag.Name)
ipcapiURL = ipcEndpoint(filepath.Join(givenPath, "clef.ipc"), configDir) ipcapiURL = ipcEndpoint(filepath.Join(givenPath, "clef.ipc"), configDir)
listener, _, err := rpc.StartIPCEndpoint(ipcapiURL, rpcAPI) listener, _, err := rpc.StartIPCEndpoint(ipcapiURL, rpcAPI)
if err != nil { if err != nil {
@ -693,7 +636,7 @@ func signer(c *cli.Context) error {
}() }()
} }
if c.GlobalBool(testFlag.Name) { if c.Bool(testFlag.Name) {
log.Info("Performing UI test") log.Info("Performing UI test")
go testExternalUI(apiImpl) go testExternalUI(apiImpl)
} }
@ -719,7 +662,7 @@ func signer(c *cli.Context) error {
// persistence requirements. // persistence requirements.
func DefaultConfigDir() string { func DefaultConfigDir() string {
// Try to place the data folder in the user's home dir // Try to place the data folder in the user's home dir
home := utils.HomeDir() home := flags.HomeDir()
if home != "" { if home != "" {
if runtime.GOOS == "darwin" { if runtime.GOOS == "darwin" {
return filepath.Join(home, "Library", "Signer") return filepath.Join(home, "Library", "Signer")
@ -739,10 +682,10 @@ func DefaultConfigDir() string {
func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) { func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) {
var ( var (
file string file string
configDir = ctx.GlobalString(configdirFlag.Name) configDir = ctx.String(configdirFlag.Name)
) )
if ctx.GlobalIsSet(signerSecretFlag.Name) { if ctx.IsSet(signerSecretFlag.Name) {
file = ctx.GlobalString(signerSecretFlag.Name) file = ctx.String(signerSecretFlag.Name)
} else { } else {
file = filepath.Join(configDir, "masterseed.json") file = filepath.Join(configDir, "masterseed.json")
} }
@ -995,7 +938,7 @@ func decryptSeed(keyjson []byte, auth string) ([]byte, error) {
} }
// GenDoc outputs examples of all structures used in json-rpc communication // GenDoc outputs examples of all structures used in json-rpc communication
func GenDoc(ctx *cli.Context) { func GenDoc(ctx *cli.Context) error {
var ( var (
a = common.HexToAddress("0xdeadbeef000000000000000000000000deadbeef") a = common.HexToAddress("0xdeadbeef000000000000000000000000deadbeef")
@ -1145,4 +1088,5 @@ These data types are defined in the channel between clef and the UI`)
for _, elem := range output { for _, elem := range output {
fmt.Println(elem) fmt.Println(elem)
} }
return nil
} }

View File

@ -28,14 +28,14 @@ import (
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
discv4Command = cli.Command{ discv4Command = &cli.Command{
Name: "discv4", Name: "discv4",
Usage: "Node Discovery v4 tools", Usage: "Node Discovery v4 tools",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
discv4PingCommand, discv4PingCommand,
discv4RequestRecordCommand, discv4RequestRecordCommand,
discv4ResolveCommand, discv4ResolveCommand,
@ -44,39 +44,39 @@ var (
discv4TestCommand, discv4TestCommand,
}, },
} }
discv4PingCommand = cli.Command{ discv4PingCommand = &cli.Command{
Name: "ping", Name: "ping",
Usage: "Sends ping to a node", Usage: "Sends ping to a node",
Action: discv4Ping, Action: discv4Ping,
ArgsUsage: "<node>", ArgsUsage: "<node>",
} }
discv4RequestRecordCommand = cli.Command{ discv4RequestRecordCommand = &cli.Command{
Name: "requestenr", Name: "requestenr",
Usage: "Requests a node record using EIP-868 enrRequest", Usage: "Requests a node record using EIP-868 enrRequest",
Action: discv4RequestRecord, Action: discv4RequestRecord,
ArgsUsage: "<node>", ArgsUsage: "<node>",
} }
discv4ResolveCommand = cli.Command{ discv4ResolveCommand = &cli.Command{
Name: "resolve", Name: "resolve",
Usage: "Finds a node in the DHT", Usage: "Finds a node in the DHT",
Action: discv4Resolve, Action: discv4Resolve,
ArgsUsage: "<node>", ArgsUsage: "<node>",
Flags: []cli.Flag{bootnodesFlag}, Flags: []cli.Flag{bootnodesFlag},
} }
discv4ResolveJSONCommand = cli.Command{ discv4ResolveJSONCommand = &cli.Command{
Name: "resolve-json", Name: "resolve-json",
Usage: "Re-resolves nodes in a nodes.json file", Usage: "Re-resolves nodes in a nodes.json file",
Action: discv4ResolveJSON, Action: discv4ResolveJSON,
Flags: []cli.Flag{bootnodesFlag}, Flags: []cli.Flag{bootnodesFlag},
ArgsUsage: "<nodes.json file>", ArgsUsage: "<nodes.json file>",
} }
discv4CrawlCommand = cli.Command{ discv4CrawlCommand = &cli.Command{
Name: "crawl", Name: "crawl",
Usage: "Updates a nodes.json file with random nodes found in the DHT", Usage: "Updates a nodes.json file with random nodes found in the DHT",
Action: discv4Crawl, Action: discv4Crawl,
Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag}, Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag},
} }
discv4TestCommand = cli.Command{ discv4TestCommand = &cli.Command{
Name: "test", Name: "test",
Usage: "Runs tests against a node", Usage: "Runs tests against a node",
Action: discv4Test, Action: discv4Test,
@ -91,31 +91,31 @@ var (
) )
var ( var (
bootnodesFlag = cli.StringFlag{ bootnodesFlag = &cli.StringFlag{
Name: "bootnodes", Name: "bootnodes",
Usage: "Comma separated nodes used for bootstrapping", Usage: "Comma separated nodes used for bootstrapping",
} }
nodekeyFlag = cli.StringFlag{ nodekeyFlag = &cli.StringFlag{
Name: "nodekey", Name: "nodekey",
Usage: "Hex-encoded node key", Usage: "Hex-encoded node key",
} }
nodedbFlag = cli.StringFlag{ nodedbFlag = &cli.StringFlag{
Name: "nodedb", Name: "nodedb",
Usage: "Nodes database location", Usage: "Nodes database location",
} }
listenAddrFlag = cli.StringFlag{ listenAddrFlag = &cli.StringFlag{
Name: "addr", Name: "addr",
Usage: "Listening address", Usage: "Listening address",
} }
crawlTimeoutFlag = cli.DurationFlag{ crawlTimeoutFlag = &cli.DurationFlag{
Name: "timeout", Name: "timeout",
Usage: "Time limit for the crawl.", Usage: "Time limit for the crawl.",
Value: 30 * time.Minute, Value: 30 * time.Minute,
} }
remoteEnodeFlag = cli.StringFlag{ remoteEnodeFlag = &cli.StringFlag{
Name: "remote", Name: "remote",
Usage: "Enode of the remote node under test", Usage: "Enode of the remote node under test",
EnvVar: "REMOTE_ENODE", EnvVars: []string{"REMOTE_ENODE"},
} }
) )

View File

@ -23,14 +23,14 @@ import (
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v5test" "github.com/ethereum/go-ethereum/cmd/devp2p/internal/v5test"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
discv5Command = cli.Command{ discv5Command = &cli.Command{
Name: "discv5", Name: "discv5",
Usage: "Node Discovery v5 tools", Usage: "Node Discovery v5 tools",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
discv5PingCommand, discv5PingCommand,
discv5ResolveCommand, discv5ResolveCommand,
discv5CrawlCommand, discv5CrawlCommand,
@ -38,24 +38,24 @@ var (
discv5ListenCommand, discv5ListenCommand,
}, },
} }
discv5PingCommand = cli.Command{ discv5PingCommand = &cli.Command{
Name: "ping", Name: "ping",
Usage: "Sends ping to a node", Usage: "Sends ping to a node",
Action: discv5Ping, Action: discv5Ping,
} }
discv5ResolveCommand = cli.Command{ discv5ResolveCommand = &cli.Command{
Name: "resolve", Name: "resolve",
Usage: "Finds a node in the DHT", Usage: "Finds a node in the DHT",
Action: discv5Resolve, Action: discv5Resolve,
Flags: []cli.Flag{bootnodesFlag}, Flags: []cli.Flag{bootnodesFlag},
} }
discv5CrawlCommand = cli.Command{ discv5CrawlCommand = &cli.Command{
Name: "crawl", Name: "crawl",
Usage: "Updates a nodes.json file with random nodes found in the DHT", Usage: "Updates a nodes.json file with random nodes found in the DHT",
Action: discv5Crawl, Action: discv5Crawl,
Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag}, Flags: []cli.Flag{bootnodesFlag, crawlTimeoutFlag},
} }
discv5TestCommand = cli.Command{ discv5TestCommand = &cli.Command{
Name: "test", Name: "test",
Usage: "Runs protocol tests against a node", Usage: "Runs protocol tests against a node",
Action: discv5Test, Action: discv5Test,
@ -66,7 +66,7 @@ var (
testListen2Flag, testListen2Flag,
}, },
} }
discv5ListenCommand = cli.Command{ discv5ListenCommand = &cli.Command{
Name: "listen", Name: "listen",
Usage: "Runs a node", Usage: "Runs a node",
Action: discv5Listen, Action: discv5Listen,

View File

@ -24,16 +24,16 @@ import (
"github.com/cloudflare/cloudflare-go" "github.com/cloudflare/cloudflare-go"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/ethereum/go-ethereum/p2p/dnsdisc"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
cloudflareTokenFlag = cli.StringFlag{ cloudflareTokenFlag = &cli.StringFlag{
Name: "token", Name: "token",
Usage: "CloudFlare API token", Usage: "CloudFlare API token",
EnvVar: "CLOUDFLARE_API_TOKEN", EnvVars: []string{"CLOUDFLARE_API_TOKEN"},
} }
cloudflareZoneIDFlag = cli.StringFlag{ cloudflareZoneIDFlag = &cli.StringFlag{
Name: "zoneid", Name: "zoneid",
Usage: "CloudFlare Zone ID (optional)", Usage: "CloudFlare Zone ID (optional)",
} }

View File

@ -32,7 +32,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/route53/types" "github.com/aws/aws-sdk-go-v2/service/route53/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/ethereum/go-ethereum/p2p/dnsdisc"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
const ( const (
@ -45,21 +45,21 @@ const (
) )
var ( var (
route53AccessKeyFlag = cli.StringFlag{ route53AccessKeyFlag = &cli.StringFlag{
Name: "access-key-id", Name: "access-key-id",
Usage: "AWS Access Key ID", Usage: "AWS Access Key ID",
EnvVar: "AWS_ACCESS_KEY_ID", EnvVars: []string{"AWS_ACCESS_KEY_ID"},
} }
route53AccessSecretFlag = cli.StringFlag{ route53AccessSecretFlag = &cli.StringFlag{
Name: "access-key-secret", Name: "access-key-secret",
Usage: "AWS Access Key Secret", Usage: "AWS Access Key Secret",
EnvVar: "AWS_SECRET_ACCESS_KEY", EnvVars: []string{"AWS_SECRET_ACCESS_KEY"},
} }
route53ZoneIDFlag = cli.StringFlag{ route53ZoneIDFlag = &cli.StringFlag{
Name: "zone-id", Name: "zone-id",
Usage: "Route53 Zone ID", Usage: "Route53 Zone ID",
} }
route53RegionFlag = cli.StringFlag{ route53RegionFlag = &cli.StringFlag{
Name: "aws-region", Name: "aws-region",
Usage: "AWS Region", Usage: "AWS Region",
Value: "eu-central-1", Value: "eu-central-1",

View File

@ -29,14 +29,14 @@ import (
"github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/ethereum/go-ethereum/p2p/dnsdisc"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
dnsCommand = cli.Command{ dnsCommand = &cli.Command{
Name: "dns", Name: "dns",
Usage: "DNS Discovery Commands", Usage: "DNS Discovery Commands",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
dnsSyncCommand, dnsSyncCommand,
dnsSignCommand, dnsSignCommand,
dnsTXTCommand, dnsTXTCommand,
@ -45,34 +45,34 @@ var (
dnsRoute53NukeCommand, dnsRoute53NukeCommand,
}, },
} }
dnsSyncCommand = cli.Command{ dnsSyncCommand = &cli.Command{
Name: "sync", Name: "sync",
Usage: "Download a DNS discovery tree", Usage: "Download a DNS discovery tree",
ArgsUsage: "<url> [ <directory> ]", ArgsUsage: "<url> [ <directory> ]",
Action: dnsSync, Action: dnsSync,
Flags: []cli.Flag{dnsTimeoutFlag}, Flags: []cli.Flag{dnsTimeoutFlag},
} }
dnsSignCommand = cli.Command{ dnsSignCommand = &cli.Command{
Name: "sign", Name: "sign",
Usage: "Sign a DNS discovery tree", Usage: "Sign a DNS discovery tree",
ArgsUsage: "<tree-directory> <key-file>", ArgsUsage: "<tree-directory> <key-file>",
Action: dnsSign, Action: dnsSign,
Flags: []cli.Flag{dnsDomainFlag, dnsSeqFlag}, Flags: []cli.Flag{dnsDomainFlag, dnsSeqFlag},
} }
dnsTXTCommand = cli.Command{ dnsTXTCommand = &cli.Command{
Name: "to-txt", Name: "to-txt",
Usage: "Create a DNS TXT records for a discovery tree", Usage: "Create a DNS TXT records for a discovery tree",
ArgsUsage: "<tree-directory> <output-file>", ArgsUsage: "<tree-directory> <output-file>",
Action: dnsToTXT, Action: dnsToTXT,
} }
dnsCloudflareCommand = cli.Command{ dnsCloudflareCommand = &cli.Command{
Name: "to-cloudflare", Name: "to-cloudflare",
Usage: "Deploy DNS TXT records to CloudFlare", Usage: "Deploy DNS TXT records to CloudFlare",
ArgsUsage: "<tree-directory>", ArgsUsage: "<tree-directory>",
Action: dnsToCloudflare, Action: dnsToCloudflare,
Flags: []cli.Flag{cloudflareTokenFlag, cloudflareZoneIDFlag}, Flags: []cli.Flag{cloudflareTokenFlag, cloudflareZoneIDFlag},
} }
dnsRoute53Command = cli.Command{ dnsRoute53Command = &cli.Command{
Name: "to-route53", Name: "to-route53",
Usage: "Deploy DNS TXT records to Amazon Route53", Usage: "Deploy DNS TXT records to Amazon Route53",
ArgsUsage: "<tree-directory>", ArgsUsage: "<tree-directory>",
@ -84,7 +84,7 @@ var (
route53RegionFlag, route53RegionFlag,
}, },
} }
dnsRoute53NukeCommand = cli.Command{ dnsRoute53NukeCommand = &cli.Command{
Name: "nuke-route53", Name: "nuke-route53",
Usage: "Deletes DNS TXT records of a subdomain on Amazon Route53", Usage: "Deletes DNS TXT records of a subdomain on Amazon Route53",
ArgsUsage: "<domain>", ArgsUsage: "<domain>",
@ -99,15 +99,15 @@ var (
) )
var ( var (
dnsTimeoutFlag = cli.DurationFlag{ dnsTimeoutFlag = &cli.DurationFlag{
Name: "timeout", Name: "timeout",
Usage: "Timeout for DNS lookups", Usage: "Timeout for DNS lookups",
} }
dnsDomainFlag = cli.StringFlag{ dnsDomainFlag = &cli.StringFlag{
Name: "domain", Name: "domain",
Usage: "Domain name of the tree", Usage: "Domain name of the tree",
} }
dnsSeqFlag = cli.UintFlag{ dnsSeqFlag = &cli.UintFlag{
Name: "seq", Name: "seq",
Usage: "New sequence number of the tree", Usage: "New sequence number of the tree",
} }

View File

@ -30,12 +30,12 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var fileFlag = cli.StringFlag{Name: "file"} var fileFlag = &cli.StringFlag{Name: "file"}
var enrdumpCommand = cli.Command{ var enrdumpCommand = &cli.Command{
Name: "enrdump", Name: "enrdump",
Usage: "Pretty-prints node records", Usage: "Pretty-prints node records",
Action: enrdump, Action: enrdump,
@ -62,7 +62,7 @@ func enrdump(ctx *cli.Context) error {
} }
source = string(b) source = string(b)
} else if ctx.NArg() == 1 { } else if ctx.NArg() == 1 {
source = ctx.Args()[0] source = ctx.Args().First()
} else { } else {
return fmt.Errorf("need record as argument") return fmt.Errorf("need record as argument")
} }

View File

@ -22,25 +22,25 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
keyCommand = cli.Command{ keyCommand = &cli.Command{
Name: "key", Name: "key",
Usage: "Operations on node keys", Usage: "Operations on node keys",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
keyGenerateCommand, keyGenerateCommand,
keyToNodeCommand, keyToNodeCommand,
}, },
} }
keyGenerateCommand = cli.Command{ keyGenerateCommand = &cli.Command{
Name: "generate", Name: "generate",
Usage: "Generates node key files", Usage: "Generates node key files",
ArgsUsage: "keyfile", ArgsUsage: "keyfile",
Action: genkey, Action: genkey,
} }
keyToNodeCommand = cli.Command{ keyToNodeCommand = &cli.Command{
Name: "to-enode", Name: "to-enode",
Usage: "Creates an enode URL from a node key file", Usage: "Creates an enode URL from a node key file",
ArgsUsage: "keyfile", ArgsUsage: "keyfile",
@ -50,17 +50,17 @@ var (
) )
var ( var (
hostFlag = cli.StringFlag{ hostFlag = &cli.StringFlag{
Name: "ip", Name: "ip",
Usage: "IP address of the node", Usage: "IP address of the node",
Value: "127.0.0.1", Value: "127.0.0.1",
} }
tcpPortFlag = cli.IntFlag{ tcpPortFlag = &cli.IntFlag{
Name: "tcp", Name: "tcp",
Usage: "TCP port of the node", Usage: "TCP port of the node",
Value: 30303, Value: 30303,
} }
udpPortFlag = cli.IntFlag{ udpPortFlag = &cli.IntFlag{
Name: "udp", Name: "udp",
Usage: "UDP port of the node", Usage: "UDP port of the node",
Value: 30303, Value: 30303,

View File

@ -20,12 +20,12 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
@ -45,6 +45,7 @@ func init() {
// Set up the CLI app. // Set up the CLI app.
app.Flags = append(app.Flags, debug.Flags...) app.Flags = append(app.Flags, debug.Flags...)
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
flags.MigrateGlobalFlags(ctx)
return debug.Setup(ctx) return debug.Setup(ctx)
} }
app.After = func(ctx *cli.Context) error { app.After = func(ctx *cli.Context) error {
@ -56,7 +57,7 @@ func init() {
os.Exit(1) os.Exit(1)
} }
// Add subcommands. // Add subcommands.
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
enrdumpCommand, enrdumpCommand,
keyCommand, keyCommand,
discv4Command, discv4Command,
@ -73,10 +74,17 @@ func main() {
// commandHasFlag returns true if the current command supports the given flag. // commandHasFlag returns true if the current command supports the given flag.
func commandHasFlag(ctx *cli.Context, flag cli.Flag) bool { func commandHasFlag(ctx *cli.Context, flag cli.Flag) bool {
flags := ctx.FlagNames() names := flag.Names()
sort.Strings(flags) set := make(map[string]struct{}, len(names))
i := sort.SearchStrings(flags, flag.GetName()) for _, name := range names {
return i != len(flags) && flags[i] == flag.GetName() set[name] = struct{}{}
}
for _, fn := range ctx.FlagNames() {
if _, ok := set[fn]; ok {
return true
}
}
return false
} }
// getNodeArg handles the common case of a single node descriptor argument. // getNodeArg handles the common case of a single node descriptor argument.
@ -84,7 +92,7 @@ func getNodeArg(ctx *cli.Context) *enode.Node {
if ctx.NArg() < 1 { if ctx.NArg() < 1 {
exit("missing node as command-line argument") exit("missing node as command-line argument")
} }
n, err := parseNode(ctx.Args()[0]) n, err := parseNode(ctx.Args().First())
if err != nil { if err != nil {
exit(err) exit(err)
} }

View File

@ -29,25 +29,25 @@ import (
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
nodesetCommand = cli.Command{ nodesetCommand = &cli.Command{
Name: "nodeset", Name: "nodeset",
Usage: "Node set tools", Usage: "Node set tools",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
nodesetInfoCommand, nodesetInfoCommand,
nodesetFilterCommand, nodesetFilterCommand,
}, },
} }
nodesetInfoCommand = cli.Command{ nodesetInfoCommand = &cli.Command{
Name: "info", Name: "info",
Usage: "Shows statistics about a node set", Usage: "Shows statistics about a node set",
Action: nodesetInfo, Action: nodesetInfo,
ArgsUsage: "<nodes.json>", ArgsUsage: "<nodes.json>",
} }
nodesetFilterCommand = cli.Command{ nodesetFilterCommand = &cli.Command{
Name: "filter", Name: "filter",
Usage: "Filters a node set", Usage: "Filters a node set",
Action: nodesetFilter, Action: nodesetFilter,

View File

@ -26,25 +26,25 @@ import (
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/rlpx" "github.com/ethereum/go-ethereum/p2p/rlpx"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
rlpxCommand = cli.Command{ rlpxCommand = &cli.Command{
Name: "rlpx", Name: "rlpx",
Usage: "RLPx Commands", Usage: "RLPx Commands",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
rlpxPingCommand, rlpxPingCommand,
rlpxEthTestCommand, rlpxEthTestCommand,
rlpxSnapTestCommand, rlpxSnapTestCommand,
}, },
} }
rlpxPingCommand = cli.Command{ rlpxPingCommand = &cli.Command{
Name: "ping", Name: "ping",
Usage: "ping <node>", Usage: "ping <node>",
Action: rlpxPing, Action: rlpxPing,
} }
rlpxEthTestCommand = cli.Command{ rlpxEthTestCommand = &cli.Command{
Name: "eth-test", Name: "eth-test",
Usage: "Runs tests against a node", Usage: "Runs tests against a node",
ArgsUsage: "<node> <chain.rlp> <genesis.json>", ArgsUsage: "<node> <chain.rlp> <genesis.json>",
@ -54,7 +54,7 @@ var (
testTAPFlag, testTAPFlag,
}, },
} }
rlpxSnapTestCommand = cli.Command{ rlpxSnapTestCommand = &cli.Command{
Name: "snap-test", Name: "snap-test",
Usage: "Runs tests against a node", Usage: "Runs tests against a node",
ArgsUsage: "<node> <chain.rlp> <genesis.json>", ArgsUsage: "<node> <chain.rlp> <genesis.json>",
@ -106,7 +106,7 @@ func rlpxEthTest(ctx *cli.Context) error {
if ctx.NArg() < 3 { if ctx.NArg() < 3 {
exit("missing path to chain.rlp as command-line argument") exit("missing path to chain.rlp as command-line argument")
} }
suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args()[1], ctx.Args()[2]) suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args().Get(1), ctx.Args().Get(2))
if err != nil { if err != nil {
exit(err) exit(err)
} }
@ -123,7 +123,7 @@ func rlpxSnapTest(ctx *cli.Context) error {
if ctx.NArg() < 3 { if ctx.NArg() < 3 {
exit("missing path to chain.rlp as command-line argument") exit("missing path to chain.rlp as command-line argument")
} }
suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args()[1], ctx.Args()[2]) suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args().Get(1), ctx.Args().Get(2))
if err != nil { if err != nil {
exit(err) exit(err)
} }

View File

@ -22,25 +22,25 @@ import (
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test" "github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test"
"github.com/ethereum/go-ethereum/internal/utesting" "github.com/ethereum/go-ethereum/internal/utesting"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
testPatternFlag = cli.StringFlag{ testPatternFlag = &cli.StringFlag{
Name: "run", Name: "run",
Usage: "Pattern of test suite(s) to run", Usage: "Pattern of test suite(s) to run",
} }
testTAPFlag = cli.BoolFlag{ testTAPFlag = &cli.BoolFlag{
Name: "tap", Name: "tap",
Usage: "Output TAP", Usage: "Output TAP",
} }
// These two are specific to the discovery tests. // These two are specific to the discovery tests.
testListen1Flag = cli.StringFlag{ testListen1Flag = &cli.StringFlag{
Name: "listen1", Name: "listen1",
Usage: "IP address of the first tester", Usage: "IP address of the first tester",
Value: v4test.Listen1, Value: v4test.Listen1,
} }
testListen2Flag = cli.StringFlag{ testListen2Flag = &cli.StringFlag{
Name: "listen2", Name: "listen2",
Usage: "IP address of the second tester", Usage: "IP address of the second tester",
Value: v4test.Listen2, Value: v4test.Listen2,
@ -53,7 +53,7 @@ func runTests(ctx *cli.Context, tests []utesting.Test) error {
tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name)) tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name))
} }
// Disable logging unless explicitly enabled. // Disable logging unless explicitly enabled.
if !ctx.GlobalIsSet("verbosity") && !ctx.GlobalIsSet("vmodule") { if !ctx.IsSet("verbosity") && !ctx.IsSet("vmodule") {
log.Root().SetHandler(log.DiscardHandler()) log.Root().SetHandler(log.DiscardHandler())
} }
// Run the tests. // Run the tests.

View File

@ -23,15 +23,15 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var newPassphraseFlag = cli.StringFlag{ var newPassphraseFlag = &cli.StringFlag{
Name: "newpasswordfile", Name: "newpasswordfile",
Usage: "the file that contains the new password for the keyfile", Usage: "the file that contains the new password for the keyfile",
} }
var commandChangePassphrase = cli.Command{ var commandChangePassphrase = &cli.Command{
Name: "changepassword", Name: "changepassword",
Usage: "change the password on a keyfile", Usage: "change the password on a keyfile",
ArgsUsage: "<keyfile>", ArgsUsage: "<keyfile>",

View File

@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/google/uuid" "github.com/google/uuid"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
type outputGenerate struct { type outputGenerate struct {
@ -35,17 +35,17 @@ type outputGenerate struct {
} }
var ( var (
privateKeyFlag = cli.StringFlag{ privateKeyFlag = &cli.StringFlag{
Name: "privatekey", Name: "privatekey",
Usage: "file containing a raw private key to encrypt", Usage: "file containing a raw private key to encrypt",
} }
lightKDFFlag = cli.BoolFlag{ lightKDFFlag = &cli.BoolFlag{
Name: "lightkdf", Name: "lightkdf",
Usage: "use less secure scrypt parameters", Usage: "use less secure scrypt parameters",
} }
) )
var commandGenerate = cli.Command{ var commandGenerate = &cli.Command{
Name: "generate", Name: "generate",
Usage: "generate new keyfile", Usage: "generate new keyfile",
ArgsUsage: "[ <keyfile> ]", ArgsUsage: "[ <keyfile> ]",

View File

@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
type outputInspect struct { type outputInspect struct {
@ -34,13 +34,13 @@ type outputInspect struct {
} }
var ( var (
privateFlag = cli.BoolFlag{ privateFlag = &cli.BoolFlag{
Name: "private", Name: "private",
Usage: "include the private key in the output", Usage: "include the private key in the output",
} }
) )
var commandInspect = cli.Command{ var commandInspect = &cli.Command{
Name: "inspect", Name: "inspect",
Usage: "inspect a keyfile", Usage: "inspect a keyfile",
ArgsUsage: "<keyfile>", ArgsUsage: "<keyfile>",

View File

@ -21,7 +21,7 @@ import (
"os" "os"
"github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/flags"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
const ( const (
@ -36,23 +36,22 @@ var app *cli.App
func init() { func init() {
app = flags.NewApp(gitCommit, gitDate, "an Ethereum key manager") app = flags.NewApp(gitCommit, gitDate, "an Ethereum key manager")
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
commandGenerate, commandGenerate,
commandInspect, commandInspect,
commandChangePassphrase, commandChangePassphrase,
commandSignMessage, commandSignMessage,
commandVerifyMessage, commandVerifyMessage,
} }
cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate
} }
// Commonly used command line flags. // Commonly used command line flags.
var ( var (
passphraseFlag = cli.StringFlag{ passphraseFlag = &cli.StringFlag{
Name: "passwordfile", Name: "passwordfile",
Usage: "the file that contains the password for the keyfile", Usage: "the file that contains the password for the keyfile",
} }
jsonFlag = cli.BoolFlag{ jsonFlag = &cli.BoolFlag{
Name: "json", Name: "json",
Usage: "output JSON instead of human-readable format", Usage: "output JSON instead of human-readable format",
} }

View File

@ -26,19 +26,19 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
type outputSign struct { type outputSign struct {
Signature string Signature string
} }
var msgfileFlag = cli.StringFlag{ var msgfileFlag = &cli.StringFlag{
Name: "msgfile", Name: "msgfile",
Usage: "file containing the message to sign/verify", Usage: "file containing the message to sign/verify",
} }
var commandSignMessage = cli.Command{ var commandSignMessage = &cli.Command{
Name: "signmessage", Name: "signmessage",
Usage: "sign a message", Usage: "sign a message",
ArgsUsage: "<keyfile> <message>", ArgsUsage: "<keyfile> <message>",
@ -89,7 +89,7 @@ type outputVerify struct {
RecoveredPublicKey string RecoveredPublicKey string
} }
var commandVerifyMessage = cli.Command{ var commandVerifyMessage = &cli.Command{
Name: "verifymessage", Name: "verifymessage",
Usage: "verify the signature of a signed message", Usage: "verify the signature of a signed message",
ArgsUsage: "<address> <signature> <message>", ArgsUsage: "<address> <signature> <message>",
@ -144,7 +144,7 @@ It is possible to refer to a file containing the message.`,
func getMessage(ctx *cli.Context, msgarg int) []byte { func getMessage(ctx *cli.Context, msgarg int) []byte {
if file := ctx.String(msgfileFlag.Name); file != "" { if file := ctx.String(msgfileFlag.Name); file != "" {
if len(ctx.Args()) > msgarg { if ctx.NArg() > msgarg {
utils.Fatalf("Can't use --msgfile and message argument at the same time.") utils.Fatalf("Can't use --msgfile and message argument at the same time.")
} }
msg, err := os.ReadFile(file) msg, err := os.ReadFile(file)
@ -152,9 +152,9 @@ func getMessage(ctx *cli.Context, msgarg int) []byte {
utils.Fatalf("Can't read message file: %v", err) utils.Fatalf("Can't read message file: %v", err)
} }
return msg return msg
} else if len(ctx.Args()) == msgarg+1 { } else if ctx.NArg() == msgarg+1 {
return []byte(ctx.Args().Get(msgarg)) return []byte(ctx.Args().Get(msgarg))
} }
utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, len(ctx.Args())) utils.Fatalf("Invalid number of arguments: want %d, got %d", msgarg+1, ctx.NArg())
return nil return nil
} }

View File

@ -23,7 +23,7 @@ import (
"strings" "strings"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
// getPassphrase obtains a passphrase given by the user. It first checks the // getPassphrase obtains a passphrase given by the user. It first checks the

View File

@ -23,10 +23,10 @@ import (
"github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var compileCommand = cli.Command{ var compileCommand = &cli.Command{
Action: compileCmd, Action: compileCmd,
Name: "compile", Name: "compile",
Usage: "compiles easm source to evm binary", Usage: "compiles easm source to evm binary",
@ -34,7 +34,7 @@ var compileCommand = cli.Command{
} }
func compileCmd(ctx *cli.Context) error { func compileCmd(ctx *cli.Context) error {
debug := ctx.GlobalBool(DebugFlag.Name) debug := ctx.Bool(DebugFlag.Name)
if len(ctx.Args().First()) == 0 { if len(ctx.Args().First()) == 0 {
return errors.New("filename required") return errors.New("filename required")

View File

@ -23,10 +23,10 @@ import (
"strings" "strings"
"github.com/ethereum/go-ethereum/core/asm" "github.com/ethereum/go-ethereum/core/asm"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var disasmCommand = cli.Command{ var disasmCommand = &cli.Command{
Action: disasmCmd, Action: disasmCmd,
Name: "disasm", Name: "disasm",
Usage: "disassembles evm binary", Usage: "disassembles evm binary",
@ -43,8 +43,8 @@ func disasmCmd(ctx *cli.Context) error {
return err return err
} }
in = string(input) in = string(input)
case ctx.GlobalIsSet(InputFlag.Name): case ctx.IsSet(InputFlag.Name):
in = ctx.GlobalString(InputFlag.Name) in = ctx.String(InputFlag.Name)
default: default:
return errors.New("missing filename or --input value") return errors.New("missing filename or --input value")
} }

View File

@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
//go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go //go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go

View File

@ -22,45 +22,47 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
TraceFlag = cli.BoolFlag{ TraceFlag = &cli.BoolFlag{
Name: "trace", Name: "trace",
Usage: "Output full trace logs to files <txhash>.jsonl", Usage: "Output full trace logs to files <txhash>.jsonl",
} }
TraceDisableMemoryFlag = cli.BoolTFlag{ TraceDisableMemoryFlag = &cli.BoolFlag{
Name: "trace.nomemory", Name: "trace.nomemory",
Value: true,
Usage: "Disable full memory dump in traces (deprecated)", Usage: "Disable full memory dump in traces (deprecated)",
} }
TraceEnableMemoryFlag = cli.BoolFlag{ TraceEnableMemoryFlag = &cli.BoolFlag{
Name: "trace.memory", Name: "trace.memory",
Usage: "Enable full memory dump in traces", Usage: "Enable full memory dump in traces",
} }
TraceDisableStackFlag = cli.BoolFlag{ TraceDisableStackFlag = &cli.BoolFlag{
Name: "trace.nostack", Name: "trace.nostack",
Usage: "Disable stack output in traces", Usage: "Disable stack output in traces",
} }
TraceDisableReturnDataFlag = cli.BoolTFlag{ TraceDisableReturnDataFlag = &cli.BoolFlag{
Name: "trace.noreturndata", Name: "trace.noreturndata",
Value: true,
Usage: "Disable return data output in traces (deprecated)", Usage: "Disable return data output in traces (deprecated)",
} }
TraceEnableReturnDataFlag = cli.BoolFlag{ TraceEnableReturnDataFlag = &cli.BoolFlag{
Name: "trace.returndata", Name: "trace.returndata",
Usage: "Enable return data output in traces", Usage: "Enable return data output in traces",
} }
OutputBasedir = cli.StringFlag{ OutputBasedir = &cli.StringFlag{
Name: "output.basedir", Name: "output.basedir",
Usage: "Specifies where output files are placed. Will be created if it does not exist.", Usage: "Specifies where output files are placed. Will be created if it does not exist.",
Value: "", Value: "",
} }
OutputBodyFlag = cli.StringFlag{ OutputBodyFlag = &cli.StringFlag{
Name: "output.body", Name: "output.body",
Usage: "If set, the RLP of the transactions (block body) will be written to this file.", Usage: "If set, the RLP of the transactions (block body) will be written to this file.",
Value: "", Value: "",
} }
OutputAllocFlag = cli.StringFlag{ OutputAllocFlag = &cli.StringFlag{
Name: "output.alloc", Name: "output.alloc",
Usage: "Determines where to put the `alloc` of the post-state.\n" + Usage: "Determines where to put the `alloc` of the post-state.\n" +
"\t`stdout` - into the stdout output\n" + "\t`stdout` - into the stdout output\n" +
@ -68,7 +70,7 @@ var (
"\t<file> - into the file <file> ", "\t<file> - into the file <file> ",
Value: "alloc.json", Value: "alloc.json",
} }
OutputResultFlag = cli.StringFlag{ OutputResultFlag = &cli.StringFlag{
Name: "output.result", Name: "output.result",
Usage: "Determines where to put the `result` (stateroot, txroot etc) of the post-state.\n" + Usage: "Determines where to put the `result` (stateroot, txroot etc) of the post-state.\n" +
"\t`stdout` - into the stdout output\n" + "\t`stdout` - into the stdout output\n" +
@ -76,7 +78,7 @@ var (
"\t<file> - into the file <file> ", "\t<file> - into the file <file> ",
Value: "result.json", Value: "result.json",
} }
OutputBlockFlag = cli.StringFlag{ OutputBlockFlag = &cli.StringFlag{
Name: "output.block", Name: "output.block",
Usage: "Determines where to put the `block` after building.\n" + Usage: "Determines where to put the `block` after building.\n" +
"\t`stdout` - into the stdout output\n" + "\t`stdout` - into the stdout output\n" +
@ -84,65 +86,65 @@ var (
"\t<file> - into the file <file> ", "\t<file> - into the file <file> ",
Value: "block.json", Value: "block.json",
} }
InputAllocFlag = cli.StringFlag{ InputAllocFlag = &cli.StringFlag{
Name: "input.alloc", Name: "input.alloc",
Usage: "`stdin` or file name of where to find the prestate alloc to use.", Usage: "`stdin` or file name of where to find the prestate alloc to use.",
Value: "alloc.json", Value: "alloc.json",
} }
InputEnvFlag = cli.StringFlag{ InputEnvFlag = &cli.StringFlag{
Name: "input.env", Name: "input.env",
Usage: "`stdin` or file name of where to find the prestate env to use.", Usage: "`stdin` or file name of where to find the prestate env to use.",
Value: "env.json", Value: "env.json",
} }
InputTxsFlag = cli.StringFlag{ InputTxsFlag = &cli.StringFlag{
Name: "input.txs", Name: "input.txs",
Usage: "`stdin` or file name of where to find the transactions to apply. " + Usage: "`stdin` or file name of where to find the transactions to apply. " +
"If the file extension is '.rlp', then the data is interpreted as an RLP list of signed transactions." + "If the file extension is '.rlp', then the data is interpreted as an RLP list of signed transactions." +
"The '.rlp' format is identical to the output.body format.", "The '.rlp' format is identical to the output.body format.",
Value: "txs.json", Value: "txs.json",
} }
InputHeaderFlag = cli.StringFlag{ InputHeaderFlag = &cli.StringFlag{
Name: "input.header", Name: "input.header",
Usage: "`stdin` or file name of where to find the block header to use.", Usage: "`stdin` or file name of where to find the block header to use.",
Value: "header.json", Value: "header.json",
} }
InputOmmersFlag = cli.StringFlag{ InputOmmersFlag = &cli.StringFlag{
Name: "input.ommers", Name: "input.ommers",
Usage: "`stdin` or file name of where to find the list of ommer header RLPs to use.", Usage: "`stdin` or file name of where to find the list of ommer header RLPs to use.",
} }
InputTxsRlpFlag = cli.StringFlag{ InputTxsRlpFlag = &cli.StringFlag{
Name: "input.txs", Name: "input.txs",
Usage: "`stdin` or file name of where to find the transactions list in RLP form.", Usage: "`stdin` or file name of where to find the transactions list in RLP form.",
Value: "txs.rlp", Value: "txs.rlp",
} }
SealCliqueFlag = cli.StringFlag{ SealCliqueFlag = &cli.StringFlag{
Name: "seal.clique", Name: "seal.clique",
Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.", Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.",
} }
SealEthashFlag = cli.BoolFlag{ SealEthashFlag = &cli.BoolFlag{
Name: "seal.ethash", Name: "seal.ethash",
Usage: "Seal block with ethash.", Usage: "Seal block with ethash.",
} }
SealEthashDirFlag = cli.StringFlag{ SealEthashDirFlag = &cli.StringFlag{
Name: "seal.ethash.dir", Name: "seal.ethash.dir",
Usage: "Path to ethash DAG. If none exists, a new DAG will be generated.", Usage: "Path to ethash DAG. If none exists, a new DAG will be generated.",
} }
SealEthashModeFlag = cli.StringFlag{ SealEthashModeFlag = &cli.StringFlag{
Name: "seal.ethash.mode", Name: "seal.ethash.mode",
Usage: "Defines the type and amount of PoW verification an ethash engine makes.", Usage: "Defines the type and amount of PoW verification an ethash engine makes.",
Value: "normal", Value: "normal",
} }
RewardFlag = cli.Int64Flag{ RewardFlag = &cli.Int64Flag{
Name: "state.reward", Name: "state.reward",
Usage: "Mining reward. Set to -1 to disable", Usage: "Mining reward. Set to -1 to disable",
Value: 0, Value: 0,
} }
ChainIDFlag = cli.Int64Flag{ ChainIDFlag = &cli.Int64Flag{
Name: "state.chainid", Name: "state.chainid",
Usage: "ChainID to use", Usage: "ChainID to use",
Value: 1, Value: 1,
} }
ForknameFlag = cli.StringFlag{ ForknameFlag = &cli.StringFlag{
Name: "state.fork", Name: "state.fork",
Usage: fmt.Sprintf("Name of ruleset to use."+ Usage: fmt.Sprintf("Name of ruleset to use."+
"\n\tAvailable forknames:"+ "\n\tAvailable forknames:"+
@ -154,7 +156,7 @@ var (
strings.Join(vm.ActivateableEips(), ", ")), strings.Join(vm.ActivateableEips(), ", ")),
Value: "GrayGlacier", Value: "GrayGlacier",
} }
VerbosityFlag = cli.IntFlag{ VerbosityFlag = &cli.IntFlag{
Name: "verbosity", Name: "verbosity",
Usage: "sets the verbosity level", Usage: "sets the verbosity level",
Value: 3, Value: 3,

View File

@ -32,7 +32,7 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
type result struct { type result struct {

View File

@ -38,7 +38,7 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
const ( const (

View File

@ -21,7 +21,7 @@ import (
"fmt" "fmt"
"os" "os"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
// readFile reads the json-data in the provided path and marshals into dest. // readFile reads the json-data in the provided path and marshals into dest.

View File

@ -23,115 +23,118 @@ import (
"os" "os"
"github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool" "github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/flags"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) var (
var gitDate = "" gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags)
gitDate = ""
app = flags.NewApp(gitCommit, gitDate, "the evm command line interface")
)
var ( var (
app = flags.NewApp(gitCommit, gitDate, "the evm command line interface") DebugFlag = &cli.BoolFlag{
DebugFlag = cli.BoolFlag{
Name: "debug", Name: "debug",
Usage: "output full trace logs", Usage: "output full trace logs",
} }
MemProfileFlag = cli.StringFlag{ MemProfileFlag = &cli.StringFlag{
Name: "memprofile", Name: "memprofile",
Usage: "creates a memory profile at the given path", Usage: "creates a memory profile at the given path",
} }
CPUProfileFlag = cli.StringFlag{ CPUProfileFlag = &cli.StringFlag{
Name: "cpuprofile", Name: "cpuprofile",
Usage: "creates a CPU profile at the given path", Usage: "creates a CPU profile at the given path",
} }
StatDumpFlag = cli.BoolFlag{ StatDumpFlag = &cli.BoolFlag{
Name: "statdump", Name: "statdump",
Usage: "displays stack and heap memory information", Usage: "displays stack and heap memory information",
} }
CodeFlag = cli.StringFlag{ CodeFlag = &cli.StringFlag{
Name: "code", Name: "code",
Usage: "EVM code", Usage: "EVM code",
} }
CodeFileFlag = cli.StringFlag{ CodeFileFlag = &cli.StringFlag{
Name: "codefile", Name: "codefile",
Usage: "File containing EVM code. If '-' is specified, code is read from stdin ", Usage: "File containing EVM code. If '-' is specified, code is read from stdin ",
} }
GasFlag = cli.Uint64Flag{ GasFlag = &cli.Uint64Flag{
Name: "gas", Name: "gas",
Usage: "gas limit for the evm", Usage: "gas limit for the evm",
Value: 10000000000, Value: 10000000000,
} }
PriceFlag = utils.BigFlag{ PriceFlag = &flags.BigFlag{
Name: "price", Name: "price",
Usage: "price set for the evm", Usage: "price set for the evm",
Value: new(big.Int), Value: new(big.Int),
} }
ValueFlag = utils.BigFlag{ ValueFlag = &flags.BigFlag{
Name: "value", Name: "value",
Usage: "value set for the evm", Usage: "value set for the evm",
Value: new(big.Int), Value: new(big.Int),
} }
DumpFlag = cli.BoolFlag{ DumpFlag = &cli.BoolFlag{
Name: "dump", Name: "dump",
Usage: "dumps the state after the run", Usage: "dumps the state after the run",
} }
InputFlag = cli.StringFlag{ InputFlag = &cli.StringFlag{
Name: "input", Name: "input",
Usage: "input for the EVM", Usage: "input for the EVM",
} }
InputFileFlag = cli.StringFlag{ InputFileFlag = &cli.StringFlag{
Name: "inputfile", Name: "inputfile",
Usage: "file containing input for the EVM", Usage: "file containing input for the EVM",
} }
VerbosityFlag = cli.IntFlag{ VerbosityFlag = &cli.IntFlag{
Name: "verbosity", Name: "verbosity",
Usage: "sets the verbosity level", Usage: "sets the verbosity level",
} }
BenchFlag = cli.BoolFlag{ BenchFlag = &cli.BoolFlag{
Name: "bench", Name: "bench",
Usage: "benchmark the execution", Usage: "benchmark the execution",
} }
CreateFlag = cli.BoolFlag{ CreateFlag = &cli.BoolFlag{
Name: "create", Name: "create",
Usage: "indicates the action should be create rather than call", Usage: "indicates the action should be create rather than call",
} }
GenesisFlag = cli.StringFlag{ GenesisFlag = &cli.StringFlag{
Name: "prestate", Name: "prestate",
Usage: "JSON file with prestate (genesis) config", Usage: "JSON file with prestate (genesis) config",
} }
MachineFlag = cli.BoolFlag{ MachineFlag = &cli.BoolFlag{
Name: "json", Name: "json",
Usage: "output trace logs in machine readable format (json)", Usage: "output trace logs in machine readable format (json)",
} }
SenderFlag = cli.StringFlag{ SenderFlag = &cli.StringFlag{
Name: "sender", Name: "sender",
Usage: "The transaction origin", Usage: "The transaction origin",
} }
ReceiverFlag = cli.StringFlag{ ReceiverFlag = &cli.StringFlag{
Name: "receiver", Name: "receiver",
Usage: "The transaction receiver (execution context)", Usage: "The transaction receiver (execution context)",
} }
DisableMemoryFlag = cli.BoolTFlag{ DisableMemoryFlag = &cli.BoolFlag{
Name: "nomemory", Name: "nomemory",
Value: true,
Usage: "disable memory output", Usage: "disable memory output",
} }
DisableStackFlag = cli.BoolFlag{ DisableStackFlag = &cli.BoolFlag{
Name: "nostack", Name: "nostack",
Usage: "disable stack output", Usage: "disable stack output",
} }
DisableStorageFlag = cli.BoolFlag{ DisableStorageFlag = &cli.BoolFlag{
Name: "nostorage", Name: "nostorage",
Usage: "disable storage output", Usage: "disable storage output",
} }
DisableReturnDataFlag = cli.BoolTFlag{ DisableReturnDataFlag = &cli.BoolFlag{
Name: "noreturndata", Name: "noreturndata",
Value: true,
Usage: "enable return data output", Usage: "enable return data output",
} }
) )
var stateTransitionCommand = cli.Command{ var stateTransitionCommand = &cli.Command{
Name: "transition", Name: "transition",
Aliases: []string{"t8n"}, Aliases: []string{"t8n"},
Usage: "executes a full state transition", Usage: "executes a full state transition",
@ -156,7 +159,8 @@ var stateTransitionCommand = cli.Command{
t8ntool.VerbosityFlag, t8ntool.VerbosityFlag,
}, },
} }
var transactionCommand = cli.Command{
var transactionCommand = &cli.Command{
Name: "transaction", Name: "transaction",
Aliases: []string{"t9n"}, Aliases: []string{"t9n"},
Usage: "performs transaction validation", Usage: "performs transaction validation",
@ -169,7 +173,7 @@ var transactionCommand = cli.Command{
}, },
} }
var blockBuilderCommand = cli.Command{ var blockBuilderCommand = &cli.Command{
Name: "block-builder", Name: "block-builder",
Aliases: []string{"b11r"}, Aliases: []string{"b11r"},
Usage: "builds a block", Usage: "builds a block",
@ -214,7 +218,7 @@ func init() {
DisableStorageFlag, DisableStorageFlag,
DisableReturnDataFlag, DisableReturnDataFlag,
} }
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
compileCommand, compileCommand,
disasmCommand, disasmCommand,
runCommand, runCommand,
@ -223,7 +227,6 @@ func init() {
transactionCommand, transactionCommand,
blockBuilderCommand, blockBuilderCommand,
} }
cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate
} }
func main() { func main() {

View File

@ -37,12 +37,13 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/core/vm/runtime" "github.com/ethereum/go-ethereum/core/vm/runtime"
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var runCommand = cli.Command{ var runCommand = &cli.Command{
Action: runCmd, Action: runCmd,
Name: "run", Name: "run",
Usage: "run arbitrary evm binary", Usage: "run arbitrary evm binary",
@ -106,14 +107,14 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []by
func runCmd(ctx *cli.Context) error { func runCmd(ctx *cli.Context) error {
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
log.Root().SetHandler(glogger) log.Root().SetHandler(glogger)
logconfig := &logger.Config{ logconfig := &logger.Config{
EnableMemory: !ctx.GlobalBool(DisableMemoryFlag.Name), EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
DisableStack: ctx.GlobalBool(DisableStackFlag.Name), DisableStack: ctx.Bool(DisableStackFlag.Name),
DisableStorage: ctx.GlobalBool(DisableStorageFlag.Name), DisableStorage: ctx.Bool(DisableStorageFlag.Name),
EnableReturnData: !ctx.GlobalBool(DisableReturnDataFlag.Name), EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
Debug: ctx.GlobalBool(DebugFlag.Name), Debug: ctx.Bool(DebugFlag.Name),
} }
var ( var (
@ -125,16 +126,16 @@ func runCmd(ctx *cli.Context) error {
receiver = common.BytesToAddress([]byte("receiver")) receiver = common.BytesToAddress([]byte("receiver"))
genesisConfig *core.Genesis genesisConfig *core.Genesis
) )
if ctx.GlobalBool(MachineFlag.Name) { if ctx.Bool(MachineFlag.Name) {
tracer = logger.NewJSONLogger(logconfig, os.Stdout) tracer = logger.NewJSONLogger(logconfig, os.Stdout)
} else if ctx.GlobalBool(DebugFlag.Name) { } else if ctx.Bool(DebugFlag.Name) {
debugLogger = logger.NewStructLogger(logconfig) debugLogger = logger.NewStructLogger(logconfig)
tracer = debugLogger tracer = debugLogger
} else { } else {
debugLogger = logger.NewStructLogger(logconfig) debugLogger = logger.NewStructLogger(logconfig)
} }
if ctx.GlobalString(GenesisFlag.Name) != "" { if ctx.String(GenesisFlag.Name) != "" {
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) gen := readGenesis(ctx.String(GenesisFlag.Name))
genesisConfig = gen genesisConfig = gen
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
genesis := gen.ToBlock(db) genesis := gen.ToBlock(db)
@ -144,18 +145,18 @@ func runCmd(ctx *cli.Context) error {
statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
genesisConfig = new(core.Genesis) genesisConfig = new(core.Genesis)
} }
if ctx.GlobalString(SenderFlag.Name) != "" { if ctx.String(SenderFlag.Name) != "" {
sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) sender = common.HexToAddress(ctx.String(SenderFlag.Name))
} }
statedb.CreateAccount(sender) statedb.CreateAccount(sender)
if ctx.GlobalString(ReceiverFlag.Name) != "" { if ctx.String(ReceiverFlag.Name) != "" {
receiver = common.HexToAddress(ctx.GlobalString(ReceiverFlag.Name)) receiver = common.HexToAddress(ctx.String(ReceiverFlag.Name))
} }
var code []byte var code []byte
codeFileFlag := ctx.GlobalString(CodeFileFlag.Name) codeFileFlag := ctx.String(CodeFileFlag.Name)
codeFlag := ctx.GlobalString(CodeFlag.Name) codeFlag := ctx.String(CodeFlag.Name)
// The '--code' or '--codefile' flag overrides code in state // The '--code' or '--codefile' flag overrides code in state
if codeFileFlag != "" || codeFlag != "" { if codeFileFlag != "" || codeFlag != "" {
@ -197,7 +198,7 @@ func runCmd(ctx *cli.Context) error {
} }
code = common.Hex2Bytes(bin) code = common.Hex2Bytes(bin)
} }
initialGas := ctx.GlobalUint64(GasFlag.Name) initialGas := ctx.Uint64(GasFlag.Name)
if genesisConfig.GasLimit != 0 { if genesisConfig.GasLimit != 0 {
initialGas = genesisConfig.GasLimit initialGas = genesisConfig.GasLimit
} }
@ -205,19 +206,19 @@ func runCmd(ctx *cli.Context) error {
Origin: sender, Origin: sender,
State: statedb, State: statedb,
GasLimit: initialGas, GasLimit: initialGas,
GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), GasPrice: flags.GlobalBig(ctx, PriceFlag.Name),
Value: utils.GlobalBig(ctx, ValueFlag.Name), Value: flags.GlobalBig(ctx, ValueFlag.Name),
Difficulty: genesisConfig.Difficulty, Difficulty: genesisConfig.Difficulty,
Time: new(big.Int).SetUint64(genesisConfig.Timestamp), Time: new(big.Int).SetUint64(genesisConfig.Timestamp),
Coinbase: genesisConfig.Coinbase, Coinbase: genesisConfig.Coinbase,
BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), BlockNumber: new(big.Int).SetUint64(genesisConfig.Number),
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Tracer: tracer, Tracer: tracer,
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name),
}, },
} }
if cpuProfilePath := ctx.GlobalString(CPUProfileFlag.Name); cpuProfilePath != "" { if cpuProfilePath := ctx.String(CPUProfileFlag.Name); cpuProfilePath != "" {
f, err := os.Create(cpuProfilePath) f, err := os.Create(cpuProfilePath)
if err != nil { if err != nil {
fmt.Println("could not create CPU profile: ", err) fmt.Println("could not create CPU profile: ", err)
@ -237,14 +238,14 @@ func runCmd(ctx *cli.Context) error {
} }
var hexInput []byte var hexInput []byte
if inputFileFlag := ctx.GlobalString(InputFileFlag.Name); inputFileFlag != "" { if inputFileFlag := ctx.String(InputFileFlag.Name); inputFileFlag != "" {
var err error var err error
if hexInput, err = os.ReadFile(inputFileFlag); err != nil { if hexInput, err = os.ReadFile(inputFileFlag); err != nil {
fmt.Printf("could not load input from file: %v\n", err) fmt.Printf("could not load input from file: %v\n", err)
os.Exit(1) os.Exit(1)
} }
} else { } else {
hexInput = []byte(ctx.GlobalString(InputFlag.Name)) hexInput = []byte(ctx.String(InputFlag.Name))
} }
hexInput = bytes.TrimSpace(hexInput) hexInput = bytes.TrimSpace(hexInput)
if len(hexInput)%2 != 0 { if len(hexInput)%2 != 0 {
@ -254,7 +255,7 @@ func runCmd(ctx *cli.Context) error {
input := common.FromHex(string(hexInput)) input := common.FromHex(string(hexInput))
var execFunc func() ([]byte, uint64, error) var execFunc func() ([]byte, uint64, error)
if ctx.GlobalBool(CreateFlag.Name) { if ctx.Bool(CreateFlag.Name) {
input = append(code, input...) input = append(code, input...)
execFunc = func() ([]byte, uint64, error) { execFunc = func() ([]byte, uint64, error) {
output, _, gasLeft, err := runtime.Create(input, &runtimeConfig) output, _, gasLeft, err := runtime.Create(input, &runtimeConfig)
@ -269,16 +270,16 @@ func runCmd(ctx *cli.Context) error {
} }
} }
bench := ctx.GlobalBool(BenchFlag.Name) bench := ctx.Bool(BenchFlag.Name)
output, leftOverGas, stats, err := timedExec(bench, execFunc) output, leftOverGas, stats, err := timedExec(bench, execFunc)
if ctx.GlobalBool(DumpFlag.Name) { if ctx.Bool(DumpFlag.Name) {
statedb.Commit(true) statedb.Commit(true)
statedb.IntermediateRoot(true) statedb.IntermediateRoot(true)
fmt.Println(string(statedb.Dump(nil))) fmt.Println(string(statedb.Dump(nil)))
} }
if memProfilePath := ctx.GlobalString(MemProfileFlag.Name); memProfilePath != "" { if memProfilePath := ctx.String(MemProfileFlag.Name); memProfilePath != "" {
f, err := os.Create(memProfilePath) f, err := os.Create(memProfilePath)
if err != nil { if err != nil {
fmt.Println("could not create memory profile: ", err) fmt.Println("could not create memory profile: ", err)
@ -291,7 +292,7 @@ func runCmd(ctx *cli.Context) error {
f.Close() f.Close()
} }
if ctx.GlobalBool(DebugFlag.Name) { if ctx.Bool(DebugFlag.Name) {
if debugLogger != nil { if debugLogger != nil {
fmt.Fprintln(os.Stderr, "#### TRACE ####") fmt.Fprintln(os.Stderr, "#### TRACE ####")
logger.WriteTrace(os.Stderr, debugLogger.StructLogs()) logger.WriteTrace(os.Stderr, debugLogger.StructLogs())
@ -300,7 +301,7 @@ func runCmd(ctx *cli.Context) error {
logger.WriteLogs(os.Stderr, statedb.Logs()) logger.WriteLogs(os.Stderr, statedb.Logs())
} }
if bench || ctx.GlobalBool(StatDumpFlag.Name) { if bench || ctx.Bool(StatDumpFlag.Name) {
fmt.Fprintf(os.Stderr, `EVM gas used: %d fmt.Fprintf(os.Stderr, `EVM gas used: %d
execution time: %v execution time: %v
allocations: %d allocations: %d

View File

@ -28,10 +28,10 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var stateTestCommand = cli.Command{ var stateTestCommand = &cli.Command{
Action: stateTestCmd, Action: stateTestCmd,
Name: "statetest", Name: "statetest",
Usage: "executes the given state tests", Usage: "executes the given state tests",
@ -54,25 +54,25 @@ func stateTestCmd(ctx *cli.Context) error {
} }
// Configure the go-ethereum logger // Configure the go-ethereum logger
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
log.Root().SetHandler(glogger) log.Root().SetHandler(glogger)
// Configure the EVM logger // Configure the EVM logger
config := &logger.Config{ config := &logger.Config{
EnableMemory: !ctx.GlobalBool(DisableMemoryFlag.Name), EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
DisableStack: ctx.GlobalBool(DisableStackFlag.Name), DisableStack: ctx.Bool(DisableStackFlag.Name),
DisableStorage: ctx.GlobalBool(DisableStorageFlag.Name), DisableStorage: ctx.Bool(DisableStorageFlag.Name),
EnableReturnData: !ctx.GlobalBool(DisableReturnDataFlag.Name), EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
} }
var ( var (
tracer vm.EVMLogger tracer vm.EVMLogger
debugger *logger.StructLogger debugger *logger.StructLogger
) )
switch { switch {
case ctx.GlobalBool(MachineFlag.Name): case ctx.Bool(MachineFlag.Name):
tracer = logger.NewJSONLogger(config, os.Stderr) tracer = logger.NewJSONLogger(config, os.Stderr)
case ctx.GlobalBool(DebugFlag.Name): case ctx.Bool(DebugFlag.Name):
debugger = logger.NewStructLogger(config) debugger = logger.NewStructLogger(config)
tracer = debugger tracer = debugger
@ -91,7 +91,7 @@ func stateTestCmd(ctx *cli.Context) error {
// Iterate over all the tests, run them and aggregate the results // Iterate over all the tests, run them and aggregate the results
cfg := vm.Config{ cfg := vm.Config{
Tracer: tracer, Tracer: tracer,
Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), Debug: ctx.Bool(DebugFlag.Name) || ctx.Bool(MachineFlag.Name),
} }
results := make([]StatetestResult, 0, len(tests)) results := make([]StatetestResult, 0, len(tests))
for key, test := range tests { for key, test := range tests {
@ -100,13 +100,13 @@ func stateTestCmd(ctx *cli.Context) error {
result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true}
_, s, err := test.Run(st, cfg, false) _, s, err := test.Run(st, cfg, false)
// print state root for evmlab tracing // print state root for evmlab tracing
if ctx.GlobalBool(MachineFlag.Name) && s != nil { if ctx.Bool(MachineFlag.Name) && s != nil {
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", s.IntermediateRoot(false)) fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", s.IntermediateRoot(false))
} }
if err != nil { if err != nil {
// Test failed, mark as so and dump any state to aid debugging // Test failed, mark as so and dump any state to aid debugging
result.Pass, result.Error = false, err.Error() result.Pass, result.Error = false, err.Error()
if ctx.GlobalBool(DumpFlag.Name) && s != nil { if ctx.Bool(DumpFlag.Name) && s != nil {
dump := s.RawDump(nil) dump := s.RawDump(nil)
result.State = &dump result.State = &dump
} }
@ -115,7 +115,7 @@ func stateTestCmd(ctx *cli.Context) error {
results = append(results, *result) results = append(results, *result)
// Print any structured logs collected // Print any structured logs collected
if ctx.GlobalBool(DebugFlag.Name) { if ctx.Bool(DebugFlag.Name) {
if debugger != nil { if debugger != nil {
fmt.Fprintln(os.Stderr, "#### TRACE ####") fmt.Fprintln(os.Stderr, "#### TRACE ####")
logger.WriteTrace(os.Stderr, debugger.StructLogs()) logger.WriteTrace(os.Stderr, debugger.StructLogs())

View File

@ -25,29 +25,27 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
walletCommand = cli.Command{ walletCommand = &cli.Command{
Name: "wallet", Name: "wallet",
Usage: "Manage Ethereum presale wallets", Usage: "Manage Ethereum presale wallets",
ArgsUsage: "", ArgsUsage: "",
Category: "ACCOUNT COMMANDS",
Description: ` Description: `
geth wallet import /path/to/my/presale.wallet geth wallet import /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account. will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a It can be used non-interactively with the --password option taking a
passwordfile as argument containing the wallet password in plaintext.`, passwordfile as argument containing the wallet password in plaintext.`,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "import", Name: "import",
Usage: "Import Ethereum presale wallet", Usage: "Import Ethereum presale wallet",
ArgsUsage: "<keyFile>", ArgsUsage: "<keyFile>",
Action: utils.MigrateFlags(importWallet), Action: importWallet,
Category: "ACCOUNT COMMANDS",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
@ -64,10 +62,9 @@ passwordfile as argument containing the wallet password in plaintext.`,
}, },
} }
accountCommand = cli.Command{ accountCommand = &cli.Command{
Name: "account", Name: "account",
Usage: "Manage accounts", Usage: "Manage accounts",
Category: "ACCOUNT COMMANDS",
Description: ` Description: `
Manage accounts, list all existing accounts, import a private key into a new Manage accounts, list all existing accounts, import a private key into a new
@ -88,11 +85,11 @@ It is safe to transfer the entire directory or the individual keys therein
between ethereum nodes by simply copying. between ethereum nodes by simply copying.
Make sure you backup your keys regularly.`, Make sure you backup your keys regularly.`,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "list", Name: "list",
Usage: "Print summary of existing accounts", Usage: "Print summary of existing accounts",
Action: utils.MigrateFlags(accountList), Action: accountList,
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
@ -103,7 +100,7 @@ Print a short summary of all accounts`,
{ {
Name: "new", Name: "new",
Usage: "Create a new account", Usage: "Create a new account",
Action: utils.MigrateFlags(accountCreate), Action: accountCreate,
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
@ -128,7 +125,7 @@ password to file or expose in any other way.
{ {
Name: "update", Name: "update",
Usage: "Update an existing account", Usage: "Update an existing account",
Action: utils.MigrateFlags(accountUpdate), Action: accountUpdate,
ArgsUsage: "<address>", ArgsUsage: "<address>",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
@ -157,7 +154,7 @@ changing your password is only possible interactively.
{ {
Name: "import", Name: "import",
Usage: "Import a private key into a new account", Usage: "Import a private key into a new account",
Action: utils.MigrateFlags(accountImport), Action: accountImport,
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.KeyStoreDirFlag, utils.KeyStoreDirFlag,
@ -263,7 +260,7 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr
func accountCreate(ctx *cli.Context) error { func accountCreate(ctx *cli.Context) error {
cfg := gethConfig{Node: defaultNodeConfig()} cfg := gethConfig{Node: defaultNodeConfig()}
// Load config file. // Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" { if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil { if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }
@ -300,13 +297,13 @@ func accountCreate(ctx *cli.Context) error {
// accountUpdate transitions an account from a previous format to the current // accountUpdate transitions an account from a previous format to the current
// one, also providing the possibility to change the pass-phrase. // one, also providing the possibility to change the pass-phrase.
func accountUpdate(ctx *cli.Context) error { func accountUpdate(ctx *cli.Context) error {
if len(ctx.Args()) == 0 { if ctx.Args().Len() == 0 {
utils.Fatalf("No accounts specified to update") utils.Fatalf("No accounts specified to update")
} }
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
for _, addr := range ctx.Args() { for _, addr := range ctx.Args().Slice() {
account, oldPassword := unlockAccount(ks, addr, 0, nil) account, oldPassword := unlockAccount(ks, addr, 0, nil)
newPassword := utils.GetPassPhraseWithList("Please give a new password. Do not forget this password.", true, 0, nil) newPassword := utils.GetPassPhraseWithList("Please give a new password. Do not forget this password.", true, 0, nil)
if err := ks.Update(account, oldPassword, newPassword); err != nil { if err := ks.Update(account, oldPassword, newPassword); err != nil {
@ -317,10 +314,10 @@ func accountUpdate(ctx *cli.Context) error {
} }
func importWallet(ctx *cli.Context) error { func importWallet(ctx *cli.Context) error {
keyfile := ctx.Args().First() if ctx.Args().Len() != 1 {
if len(keyfile) == 0 { utils.Fatalf("keyfile must be given as the only argument")
utils.Fatalf("keyfile must be given as argument")
} }
keyfile := ctx.Args().First()
keyJSON, err := os.ReadFile(keyfile) keyJSON, err := os.ReadFile(keyfile)
if err != nil { if err != nil {
utils.Fatalf("Could not read wallet file: %v", err) utils.Fatalf("Could not read wallet file: %v", err)
@ -339,10 +336,10 @@ func importWallet(ctx *cli.Context) error {
} }
func accountImport(ctx *cli.Context) error { func accountImport(ctx *cli.Context) error {
keyfile := ctx.Args().First() if ctx.Args().Len() != 1 {
if len(keyfile) == 0 { utils.Fatalf("keyfile must be given as the only argument")
utils.Fatalf("keyfile must be given as argument")
} }
keyfile := ctx.Args().First()
key, err := crypto.LoadECDSA(keyfile) key, err := crypto.LoadECDSA(keyfile)
if err != nil { if err != nil {
utils.Fatalf("Failed to load the private key: %v", err) utils.Fatalf("Failed to load the private key: %v", err)

View File

@ -49,20 +49,27 @@ func TestAccountListEmpty(t *testing.T) {
func TestAccountList(t *testing.T) { func TestAccountList(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, "account", "list", "--datadir", datadir) var want = `
defer geth.ExpectExit()
if runtime.GOOS == "windows" {
geth.Expect(`
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz
`)
} else {
geth.Expect(`
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz
`) `
if runtime.GOOS == "windows" {
want = `
Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa
Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz
`
}
{
geth := runGeth(t, "account", "list", "--datadir", datadir)
geth.Expect(want)
geth.ExpectExit()
}
{
geth := runGeth(t, "--datadir", datadir, "account", "list")
geth.Expect(want)
geth.ExpectExit()
} }
} }
@ -110,6 +117,20 @@ func TestAccountImport(t *testing.T) {
} }
} }
func TestAccountHelp(t *testing.T) {
geth := runGeth(t, "account", "-h")
geth.WaitExit()
if have, want := geth.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want)
}
geth = runGeth(t, "account", "import", "-h")
geth.WaitExit()
if have, want := geth.ExitStatus(), 0; have != want {
t.Errorf("exit error, have %d want %d", have, want)
}
}
func importAccountWithExpect(t *testing.T, key string, expected string) { func importAccountWithExpect(t *testing.T, key string, expected string) {
dir := t.TempDir() dir := t.TempDir()
keyfile := filepath.Join(dir, "key.prv") keyfile := filepath.Join(dir, "key.prv")
@ -120,7 +141,7 @@ func importAccountWithExpect(t *testing.T, key string, expected string) {
if err := os.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil { if err := os.WriteFile(passwordFile, []byte("foobar"), 0600); err != nil {
t.Error(err) t.Error(err)
} }
geth := runGeth(t, "--lightkdf", "account", "import", keyfile, "-password", passwordFile) geth := runGeth(t, "--lightkdf", "account", "import", "-password", passwordFile, keyfile)
defer geth.ExpectExit() defer geth.ExpectExit()
geth.Expect(expected) geth.Expect(expected)
} }

View File

@ -38,17 +38,16 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
initCommand = cli.Command{ initCommand = &cli.Command{
Action: utils.MigrateFlags(initGenesis), Action: initGenesis,
Name: "init", Name: "init",
Usage: "Bootstrap and initialize a new genesis block", Usage: "Bootstrap and initialize a new genesis block",
ArgsUsage: "<genesisPath>", ArgsUsage: "<genesisPath>",
Flags: utils.DatabasePathFlags, Flags: utils.DatabasePathFlags,
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The init command initializes a new genesis block and definition for the network. The init command initializes a new genesis block and definition for the network.
This is a destructive action and changes the network in which you will be This is a destructive action and changes the network in which you will be
@ -56,18 +55,17 @@ participating.
It expects the genesis file as argument.`, It expects the genesis file as argument.`,
} }
dumpGenesisCommand = cli.Command{ dumpGenesisCommand = &cli.Command{
Action: utils.MigrateFlags(dumpGenesis), Action: dumpGenesis,
Name: "dumpgenesis", Name: "dumpgenesis",
Usage: "Dumps genesis block JSON configuration to stdout", Usage: "Dumps genesis block JSON configuration to stdout",
ArgsUsage: "", ArgsUsage: "",
Flags: utils.NetworkFlags, Flags: utils.NetworkFlags,
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The dumpgenesis command dumps the genesis block configuration in JSON format to stdout.`, The dumpgenesis command dumps the genesis block configuration in JSON format to stdout.`,
} }
importCommand = cli.Command{ importCommand = &cli.Command{
Action: utils.MigrateFlags(importChain), Action: importChain,
Name: "import", Name: "import",
Usage: "Import a blockchain file", Usage: "Import a blockchain file",
ArgsUsage: "<filename> (<filename 2> ... <filename N>) ", ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
@ -94,7 +92,6 @@ The dumpgenesis command dumps the genesis block configuration in JSON format to
utils.MetricsInfluxDBOrganizationFlag, utils.MetricsInfluxDBOrganizationFlag,
utils.TxLookupLimitFlag, utils.TxLookupLimitFlag,
}, utils.DatabasePathFlags...), }, utils.DatabasePathFlags...),
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The import command imports blocks from an RLP-encoded form. The form can be one file The import command imports blocks from an RLP-encoded form. The form can be one file
with several RLP-encoded blocks, or several files can be used. with several RLP-encoded blocks, or several files can be used.
@ -102,8 +99,8 @@ with several RLP-encoded blocks, or several files can be used.
If only one file is used, import error will result in failure. If several files are used, If only one file is used, import error will result in failure. If several files are used,
processing will proceed even if an individual RLP-file import failure occurs.`, processing will proceed even if an individual RLP-file import failure occurs.`,
} }
exportCommand = cli.Command{ exportCommand = &cli.Command{
Action: utils.MigrateFlags(exportChain), Action: exportChain,
Name: "export", Name: "export",
Usage: "Export blockchain into file", Usage: "Export blockchain into file",
ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]", ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]",
@ -111,7 +108,6 @@ processing will proceed even if an individual RLP-file import failure occurs.`,
utils.CacheFlag, utils.CacheFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.DatabasePathFlags...), }, utils.DatabasePathFlags...),
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
Requires a first argument of the file to write to. Requires a first argument of the file to write to.
Optional second and third arguments control the first and Optional second and third arguments control the first and
@ -119,8 +115,8 @@ last block to write. In this mode, the file will be appended
if already existing. If the file ends with .gz, the output will if already existing. If the file ends with .gz, the output will
be gzipped.`, be gzipped.`,
} }
importPreimagesCommand = cli.Command{ importPreimagesCommand = &cli.Command{
Action: utils.MigrateFlags(importPreimages), Action: importPreimages,
Name: "import-preimages", Name: "import-preimages",
Usage: "Import the preimage database from an RLP stream", Usage: "Import the preimage database from an RLP stream",
ArgsUsage: "<datafile>", ArgsUsage: "<datafile>",
@ -128,14 +124,13 @@ be gzipped.`,
utils.CacheFlag, utils.CacheFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.DatabasePathFlags...), }, utils.DatabasePathFlags...),
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The import-preimages command imports hash preimages from an RLP encoded stream. The import-preimages command imports hash preimages from an RLP encoded stream.
It's deprecated, please use "geth db import" instead. It's deprecated, please use "geth db import" instead.
`, `,
} }
exportPreimagesCommand = cli.Command{ exportPreimagesCommand = &cli.Command{
Action: utils.MigrateFlags(exportPreimages), Action: exportPreimages,
Name: "export-preimages", Name: "export-preimages",
Usage: "Export the preimage database into an RLP stream", Usage: "Export the preimage database into an RLP stream",
ArgsUsage: "<dumpfile>", ArgsUsage: "<dumpfile>",
@ -143,14 +138,13 @@ It's deprecated, please use "geth db import" instead.
utils.CacheFlag, utils.CacheFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.DatabasePathFlags...), }, utils.DatabasePathFlags...),
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
The export-preimages command exports hash preimages to an RLP encoded stream. The export-preimages command exports hash preimages to an RLP encoded stream.
It's deprecated, please use "geth db export" instead. It's deprecated, please use "geth db export" instead.
`, `,
} }
dumpCommand = cli.Command{ dumpCommand = &cli.Command{
Action: utils.MigrateFlags(dump), Action: dump,
Name: "dump", Name: "dump",
Usage: "Dump a specific block from storage", Usage: "Dump a specific block from storage",
ArgsUsage: "[? <blockHash> | <blockNum>]", ArgsUsage: "[? <blockHash> | <blockNum>]",
@ -163,7 +157,6 @@ It's deprecated, please use "geth db export" instead.
utils.StartKeyFlag, utils.StartKeyFlag,
utils.DumpLimitFlag, utils.DumpLimitFlag,
}, utils.DatabasePathFlags...), }, utils.DatabasePathFlags...),
Category: "BLOCKCHAIN COMMANDS",
Description: ` Description: `
This command dumps out the state for a given block (or latest, if none provided). This command dumps out the state for a given block (or latest, if none provided).
`, `,
@ -192,7 +185,7 @@ func initGenesis(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
defer stack.Close() defer stack.Close()
for _, name := range []string{"chaindata", "lightchaindata"} { for _, name := range []string{"chaindata", "lightchaindata"} {
chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.GlobalString(utils.AncientFlag.Name), "", false) chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false)
if err != nil { if err != nil {
utils.Fatalf("Failed to open database: %v", err) utils.Fatalf("Failed to open database: %v", err)
} }
@ -219,7 +212,7 @@ func dumpGenesis(ctx *cli.Context) error {
} }
func importChain(ctx *cli.Context) error { func importChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
// Start metrics export if enabled // Start metrics export if enabled
@ -253,13 +246,13 @@ func importChain(ctx *cli.Context) error {
var importErr error var importErr error
if len(ctx.Args()) == 1 { if ctx.Args().Len() == 1 {
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil { if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
importErr = err importErr = err
log.Error("Import error", "err", err) log.Error("Import error", "err", err)
} }
} else { } else {
for _, arg := range ctx.Args() { for _, arg := range ctx.Args().Slice() {
if err := utils.ImportChain(chain, arg); err != nil { if err := utils.ImportChain(chain, arg); err != nil {
importErr = err importErr = err
log.Error("Import error", "file", arg, "err", err) log.Error("Import error", "file", arg, "err", err)
@ -281,7 +274,7 @@ func importChain(ctx *cli.Context) error {
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000) fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs)) fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
if ctx.GlobalBool(utils.NoCompactionFlag.Name) { if ctx.Bool(utils.NoCompactionFlag.Name) {
return nil return nil
} }
@ -298,7 +291,7 @@ func importChain(ctx *cli.Context) error {
} }
func exportChain(ctx *cli.Context) error { func exportChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
@ -310,7 +303,7 @@ func exportChain(ctx *cli.Context) error {
var err error var err error
fp := ctx.Args().First() fp := ctx.Args().First()
if len(ctx.Args()) < 3 { if ctx.Args().Len() < 3 {
err = utils.ExportChain(chain, fp) err = utils.ExportChain(chain, fp)
} else { } else {
// This can be improved to allow for numbers larger than 9223372036854775807 // This can be improved to allow for numbers larger than 9223372036854775807
@ -337,7 +330,7 @@ func exportChain(ctx *cli.Context) error {
// importPreimages imports preimage data from the specified file. // importPreimages imports preimage data from the specified file.
func importPreimages(ctx *cli.Context) error { func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
@ -356,7 +349,7 @@ func importPreimages(ctx *cli.Context) error {
// exportPreimages dumps the preimage data to specified json file in streaming way. // exportPreimages dumps the preimage data to specified json file in streaming way.
func exportPreimages(ctx *cli.Context) error { func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 { if ctx.Args().Len() < 1 {
utils.Fatalf("This command requires an argument.") utils.Fatalf("This command requires an argument.")
} }
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)

View File

@ -25,7 +25,7 @@ import (
"reflect" "reflect"
"unicode" "unicode"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/accounts/external" "github.com/ethereum/go-ethereum/accounts/external"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
@ -43,19 +44,19 @@ import (
) )
var ( var (
dumpConfigCommand = cli.Command{ dumpConfigCommand = &cli.Command{
Action: utils.MigrateFlags(dumpConfig), Action: dumpConfig,
Name: "dumpconfig", Name: "dumpconfig",
Usage: "Show configuration values", Usage: "Show configuration values",
ArgsUsage: "", ArgsUsage: "",
Flags: utils.GroupFlags(nodeFlags, rpcFlags), Flags: utils.GroupFlags(nodeFlags, rpcFlags),
Category: "MISCELLANEOUS COMMANDS",
Description: `The dumpconfig command shows configuration values.`, Description: `The dumpconfig command shows configuration values.`,
} }
configFileFlag = cli.StringFlag{ configFileFlag = &cli.StringFlag{
Name: "config", Name: "config",
Usage: "TOML configuration file", Usage: "TOML configuration file",
Category: flags.EthCategory,
} }
) )
@ -127,7 +128,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
} }
// Load config file. // Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" { if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil { if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }
@ -145,8 +146,8 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
} }
utils.SetEthConfig(ctx, stack, &cfg.Eth) utils.SetEthConfig(ctx, stack, &cfg.Eth)
if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { if ctx.IsSet(utils.EthStatsURLFlag.Name) {
cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) cfg.Ethstats.URL = ctx.String(utils.EthStatsURLFlag.Name)
} }
applyMetricConfig(ctx, &cfg) applyMetricConfig(ctx, &cfg)
@ -156,15 +157,15 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
// makeFullNode loads geth configuration and creates the Ethereum backend. // makeFullNode loads geth configuration and creates the Ethereum backend.
func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
stack, cfg := makeConfigNode(ctx) stack, cfg := makeConfigNode(ctx)
if ctx.GlobalIsSet(utils.OverrideGrayGlacierFlag.Name) { if ctx.IsSet(utils.OverrideGrayGlacierFlag.Name) {
cfg.Eth.OverrideGrayGlacier = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideGrayGlacierFlag.Name)) cfg.Eth.OverrideGrayGlacier = new(big.Int).SetUint64(ctx.Uint64(utils.OverrideGrayGlacierFlag.Name))
} }
if ctx.GlobalIsSet(utils.OverrideTerminalTotalDifficulty.Name) { if ctx.IsSet(utils.OverrideTerminalTotalDifficulty.Name) {
cfg.Eth.OverrideTerminalTotalDifficulty = utils.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name) cfg.Eth.OverrideTerminalTotalDifficulty = flags.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name)
} }
backend, eth := utils.RegisterEthService(stack, &cfg.Eth) backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
// Warn users to migrate if they have a legacy freezer format. // Warn users to migrate if they have a legacy freezer format.
if eth != nil && !ctx.GlobalIsSet(utils.IgnoreLegacyReceiptsFlag.Name) { if eth != nil && !ctx.IsSet(utils.IgnoreLegacyReceiptsFlag.Name) {
firstIdx := uint64(0) firstIdx := uint64(0)
// Hack to speed up check for mainnet because we know // Hack to speed up check for mainnet because we know
// the first non-empty block. // the first non-empty block.
@ -182,7 +183,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
} }
// Configure GraphQL if requested // Configure GraphQL if requested
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) { if ctx.IsSet(utils.GraphQLEnabledFlag.Name) {
utils.RegisterGraphQLService(stack, backend, cfg.Node) utils.RegisterGraphQLService(stack, backend, cfg.Node)
} }
// Add the Ethereum Stats daemon if requested. // Add the Ethereum Stats daemon if requested.
@ -222,47 +223,47 @@ func dumpConfig(ctx *cli.Context) error {
} }
func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
if ctx.GlobalIsSet(utils.MetricsEnabledFlag.Name) { if ctx.IsSet(utils.MetricsEnabledFlag.Name) {
cfg.Metrics.Enabled = ctx.GlobalBool(utils.MetricsEnabledFlag.Name) cfg.Metrics.Enabled = ctx.Bool(utils.MetricsEnabledFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsEnabledExpensiveFlag.Name) { if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) {
cfg.Metrics.EnabledExpensive = ctx.GlobalBool(utils.MetricsEnabledExpensiveFlag.Name) cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsHTTPFlag.Name) { if ctx.IsSet(utils.MetricsHTTPFlag.Name) {
cfg.Metrics.HTTP = ctx.GlobalString(utils.MetricsHTTPFlag.Name) cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsPortFlag.Name) { if ctx.IsSet(utils.MetricsPortFlag.Name) {
cfg.Metrics.Port = ctx.GlobalInt(utils.MetricsPortFlag.Name) cfg.Metrics.Port = ctx.Int(utils.MetricsPortFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsEnableInfluxDBFlag.Name) { if ctx.IsSet(utils.MetricsEnableInfluxDBFlag.Name) {
cfg.Metrics.EnableInfluxDB = ctx.GlobalBool(utils.MetricsEnableInfluxDBFlag.Name) cfg.Metrics.EnableInfluxDB = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsInfluxDBEndpointFlag.Name) { if ctx.IsSet(utils.MetricsInfluxDBEndpointFlag.Name) {
cfg.Metrics.InfluxDBEndpoint = ctx.GlobalString(utils.MetricsInfluxDBEndpointFlag.Name) cfg.Metrics.InfluxDBEndpoint = ctx.String(utils.MetricsInfluxDBEndpointFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsInfluxDBDatabaseFlag.Name) { if ctx.IsSet(utils.MetricsInfluxDBDatabaseFlag.Name) {
cfg.Metrics.InfluxDBDatabase = ctx.GlobalString(utils.MetricsInfluxDBDatabaseFlag.Name) cfg.Metrics.InfluxDBDatabase = ctx.String(utils.MetricsInfluxDBDatabaseFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsInfluxDBUsernameFlag.Name) { if ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) {
cfg.Metrics.InfluxDBUsername = ctx.GlobalString(utils.MetricsInfluxDBUsernameFlag.Name) cfg.Metrics.InfluxDBUsername = ctx.String(utils.MetricsInfluxDBUsernameFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsInfluxDBPasswordFlag.Name) { if ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name) {
cfg.Metrics.InfluxDBPassword = ctx.GlobalString(utils.MetricsInfluxDBPasswordFlag.Name) cfg.Metrics.InfluxDBPassword = ctx.String(utils.MetricsInfluxDBPasswordFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsInfluxDBTagsFlag.Name) { if ctx.IsSet(utils.MetricsInfluxDBTagsFlag.Name) {
cfg.Metrics.InfluxDBTags = ctx.GlobalString(utils.MetricsInfluxDBTagsFlag.Name) cfg.Metrics.InfluxDBTags = ctx.String(utils.MetricsInfluxDBTagsFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsEnableInfluxDBV2Flag.Name) { if ctx.IsSet(utils.MetricsEnableInfluxDBV2Flag.Name) {
cfg.Metrics.EnableInfluxDBV2 = ctx.GlobalBool(utils.MetricsEnableInfluxDBV2Flag.Name) cfg.Metrics.EnableInfluxDBV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsInfluxDBTokenFlag.Name) { if ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) {
cfg.Metrics.InfluxDBToken = ctx.GlobalString(utils.MetricsInfluxDBTokenFlag.Name) cfg.Metrics.InfluxDBToken = ctx.String(utils.MetricsInfluxDBTokenFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsInfluxDBBucketFlag.Name) { if ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name) {
cfg.Metrics.InfluxDBBucket = ctx.GlobalString(utils.MetricsInfluxDBBucketFlag.Name) cfg.Metrics.InfluxDBBucket = ctx.String(utils.MetricsInfluxDBBucketFlag.Name)
} }
if ctx.GlobalIsSet(utils.MetricsInfluxDBOrganizationFlag.Name) { if ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) {
cfg.Metrics.InfluxDBOrganization = ctx.GlobalString(utils.MetricsInfluxDBOrganizationFlag.Name) cfg.Metrics.InfluxDBOrganization = ctx.String(utils.MetricsInfluxDBOrganizationFlag.Name)
} }
} }

View File

@ -24,31 +24,29 @@ import (
"github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/console"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag} consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag}
consoleCommand = cli.Command{ consoleCommand = &cli.Command{
Action: utils.MigrateFlags(localConsole), Action: localConsole,
Name: "console", Name: "console",
Usage: "Start an interactive JavaScript environment", Usage: "Start an interactive JavaScript environment",
Flags: utils.GroupFlags(nodeFlags, rpcFlags, consoleFlags), Flags: utils.GroupFlags(nodeFlags, rpcFlags, consoleFlags),
Category: "CONSOLE COMMANDS",
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://geth.ethereum.org/docs/interface/javascript-console.`, See https://geth.ethereum.org/docs/interface/javascript-console.`,
} }
attachCommand = cli.Command{ attachCommand = &cli.Command{
Action: utils.MigrateFlags(remoteConsole), Action: remoteConsole,
Name: "attach", Name: "attach",
Usage: "Start an interactive JavaScript environment (connect to node)", Usage: "Start an interactive JavaScript environment (connect to node)",
ArgsUsage: "[endpoint]", ArgsUsage: "[endpoint]",
Flags: utils.GroupFlags([]cli.Flag{utils.DataDirFlag}, consoleFlags), Flags: utils.GroupFlags([]cli.Flag{utils.DataDirFlag}, consoleFlags),
Category: "CONSOLE COMMANDS",
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
@ -56,13 +54,12 @@ See https://geth.ethereum.org/docs/interface/javascript-console.
This command allows to open a console on a running geth node.`, This command allows to open a console on a running geth node.`,
} }
javascriptCommand = cli.Command{ javascriptCommand = &cli.Command{
Action: utils.MigrateFlags(ephemeralConsole), Action: ephemeralConsole,
Name: "js", Name: "js",
Usage: "(DEPRECATED) Execute the specified JavaScript files", Usage: "(DEPRECATED) Execute the specified JavaScript files",
ArgsUsage: "<jsfile> [jsfile...]", ArgsUsage: "<jsfile> [jsfile...]",
Flags: utils.GroupFlags(nodeFlags, consoleFlags), Flags: utils.GroupFlags(nodeFlags, consoleFlags),
Category: "CONSOLE COMMANDS",
Description: ` Description: `
The JavaScript VM exposes a node admin interface as well as the Ðapp The JavaScript VM exposes a node admin interface as well as the Ðapp
JavaScript API. See https://geth.ethereum.org/docs/interface/javascript-console`, JavaScript API. See https://geth.ethereum.org/docs/interface/javascript-console`,
@ -85,7 +82,7 @@ func localConsole(ctx *cli.Context) error {
} }
config := console.Config{ config := console.Config{
DataDir: utils.MakeDataDir(ctx), DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client, Client: client,
Preload: utils.MakeConsolePreloads(ctx), Preload: utils.MakeConsolePreloads(ctx),
} }
@ -96,7 +93,7 @@ func localConsole(ctx *cli.Context) error {
defer console.Stop(false) defer console.Stop(false)
// If only a short execution was requested, evaluate and return. // If only a short execution was requested, evaluate and return.
if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { if script := ctx.String(utils.ExecFlag.Name); script != "" {
console.Evaluate(script) console.Evaluate(script)
return nil return nil
} }
@ -129,7 +126,7 @@ func remoteConsole(ctx *cli.Context) error {
} }
config := console.Config{ config := console.Config{
DataDir: utils.MakeDataDir(ctx), DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), DocRoot: ctx.String(utils.JSpathFlag.Name),
Client: client, Client: client,
Preload: utils.MakeConsolePreloads(ctx), Preload: utils.MakeConsolePreloads(ctx),
} }
@ -139,7 +136,7 @@ func remoteConsole(ctx *cli.Context) error {
} }
defer console.Stop(false) defer console.Stop(false)
if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { if script := ctx.String(utils.ExecFlag.Name); script != "" {
console.Evaluate(script) console.Evaluate(script)
return nil return nil
} }
@ -155,7 +152,7 @@ func remoteConsole(ctx *cli.Context) error {
// everything down. // everything down.
func ephemeralConsole(ctx *cli.Context) error { func ephemeralConsole(ctx *cli.Context) error {
var b strings.Builder var b strings.Builder
for _, file := range ctx.Args() { for _, file := range ctx.Args().Slice() {
b.Write([]byte(fmt.Sprintf("loadScript('%s');", file))) b.Write([]byte(fmt.Sprintf("loadScript('%s');", file)))
} }
utils.Fatalf(`The "js" command is deprecated. Please use the following instead: utils.Fatalf(`The "js" command is deprecated. Please use the following instead:

View File

@ -40,26 +40,24 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/olekukonko/tablewriter" "github.com/olekukonko/tablewriter"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
removedbCommand = cli.Command{ removedbCommand = &cli.Command{
Action: utils.MigrateFlags(removeDB), Action: removeDB,
Name: "removedb", Name: "removedb",
Usage: "Remove blockchain and state databases", Usage: "Remove blockchain and state databases",
ArgsUsage: "", ArgsUsage: "",
Flags: utils.DatabasePathFlags, Flags: utils.DatabasePathFlags,
Category: "DATABASE COMMANDS",
Description: ` Description: `
Remove blockchain and state databases`, Remove blockchain and state databases`,
} }
dbCommand = cli.Command{ dbCommand = &cli.Command{
Name: "db", Name: "db",
Usage: "Low level database operations", Usage: "Low level database operations",
ArgsUsage: "", ArgsUsage: "",
Category: "DATABASE COMMANDS", Subcommands: []*cli.Command{
Subcommands: []cli.Command{
dbInspectCmd, dbInspectCmd,
dbStatCmd, dbStatCmd,
dbCompactCmd, dbCompactCmd,
@ -75,8 +73,8 @@ Remove blockchain and state databases`,
dbCheckStateContentCmd, dbCheckStateContentCmd,
}, },
} }
dbInspectCmd = cli.Command{ dbInspectCmd = &cli.Command{
Action: utils.MigrateFlags(inspect), Action: inspect,
Name: "inspect", Name: "inspect",
ArgsUsage: "<prefix> <start>", ArgsUsage: "<prefix> <start>",
Flags: utils.GroupFlags([]cli.Flag{ Flags: utils.GroupFlags([]cli.Flag{
@ -85,8 +83,8 @@ Remove blockchain and state databases`,
Usage: "Inspect the storage size for each type of data in the database", Usage: "Inspect the storage size for each type of data in the database",
Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`, Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
} }
dbCheckStateContentCmd = cli.Command{ dbCheckStateContentCmd = &cli.Command{
Action: utils.MigrateFlags(checkStateContent), Action: checkStateContent,
Name: "check-state-content", Name: "check-state-content",
ArgsUsage: "<start (optional)>", ArgsUsage: "<start (optional)>",
Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags),
@ -95,16 +93,16 @@ Remove blockchain and state databases`,
For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates
a data corruption.`, a data corruption.`,
} }
dbStatCmd = cli.Command{ dbStatCmd = &cli.Command{
Action: utils.MigrateFlags(dbStats), Action: dbStats,
Name: "stats", Name: "stats",
Usage: "Print leveldb statistics", Usage: "Print leveldb statistics",
Flags: utils.GroupFlags([]cli.Flag{ Flags: utils.GroupFlags([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabasePathFlags), }, utils.NetworkFlags, utils.DatabasePathFlags),
} }
dbCompactCmd = cli.Command{ dbCompactCmd = &cli.Command{
Action: utils.MigrateFlags(dbCompact), Action: dbCompact,
Name: "compact", Name: "compact",
Usage: "Compact leveldb database. WARNING: May take a very long time", Usage: "Compact leveldb database. WARNING: May take a very long time",
Flags: utils.GroupFlags([]cli.Flag{ Flags: utils.GroupFlags([]cli.Flag{
@ -116,8 +114,8 @@ a data corruption.`,
WARNING: This operation may take a very long time to finish, and may cause database WARNING: This operation may take a very long time to finish, and may cause database
corruption if it is aborted during execution'!`, corruption if it is aborted during execution'!`,
} }
dbGetCmd = cli.Command{ dbGetCmd = &cli.Command{
Action: utils.MigrateFlags(dbGet), Action: dbGet,
Name: "get", Name: "get",
Usage: "Show the value of a database key", Usage: "Show the value of a database key",
ArgsUsage: "<hex-encoded key>", ArgsUsage: "<hex-encoded key>",
@ -126,8 +124,8 @@ corruption if it is aborted during execution'!`,
}, utils.NetworkFlags, utils.DatabasePathFlags), }, utils.NetworkFlags, utils.DatabasePathFlags),
Description: "This command looks up the specified database key from the database.", Description: "This command looks up the specified database key from the database.",
} }
dbDeleteCmd = cli.Command{ dbDeleteCmd = &cli.Command{
Action: utils.MigrateFlags(dbDelete), Action: dbDelete,
Name: "delete", Name: "delete",
Usage: "Delete a database key (WARNING: may corrupt your database)", Usage: "Delete a database key (WARNING: may corrupt your database)",
ArgsUsage: "<hex-encoded key>", ArgsUsage: "<hex-encoded key>",
@ -137,8 +135,8 @@ corruption if it is aborted during execution'!`,
Description: `This command deletes the specified database key from the database. Description: `This command deletes the specified database key from the database.
WARNING: This is a low-level operation which may cause database corruption!`, WARNING: This is a low-level operation which may cause database corruption!`,
} }
dbPutCmd = cli.Command{ dbPutCmd = &cli.Command{
Action: utils.MigrateFlags(dbPut), Action: dbPut,
Name: "put", Name: "put",
Usage: "Set the value of a database key (WARNING: may corrupt your database)", Usage: "Set the value of a database key (WARNING: may corrupt your database)",
ArgsUsage: "<hex-encoded key> <hex-encoded value>", ArgsUsage: "<hex-encoded key> <hex-encoded value>",
@ -148,8 +146,8 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Description: `This command sets a given database key to the given value. Description: `This command sets a given database key to the given value.
WARNING: This is a low-level operation which may cause database corruption!`, WARNING: This is a low-level operation which may cause database corruption!`,
} }
dbGetSlotsCmd = cli.Command{ dbGetSlotsCmd = &cli.Command{
Action: utils.MigrateFlags(dbDumpTrie), Action: dbDumpTrie,
Name: "dumptrie", Name: "dumptrie",
Usage: "Show the storage key/values of a given storage trie", Usage: "Show the storage key/values of a given storage trie",
ArgsUsage: "<hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>", ArgsUsage: "<hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
@ -158,8 +156,8 @@ WARNING: This is a low-level operation which may cause database corruption!`,
}, utils.NetworkFlags, utils.DatabasePathFlags), }, utils.NetworkFlags, utils.DatabasePathFlags),
Description: "This command looks up the specified database key from the database.", Description: "This command looks up the specified database key from the database.",
} }
dbDumpFreezerIndex = cli.Command{ dbDumpFreezerIndex = &cli.Command{
Action: utils.MigrateFlags(freezerInspect), Action: freezerInspect,
Name: "freezer-index", Name: "freezer-index",
Usage: "Dump out the index of a given freezer type", Usage: "Dump out the index of a given freezer type",
ArgsUsage: "<type> <start (int)> <end (int)>", ArgsUsage: "<type> <start (int)> <end (int)>",
@ -168,8 +166,8 @@ WARNING: This is a low-level operation which may cause database corruption!`,
}, utils.NetworkFlags, utils.DatabasePathFlags), }, utils.NetworkFlags, utils.DatabasePathFlags),
Description: "This command displays information about the freezer index.", Description: "This command displays information about the freezer index.",
} }
dbImportCmd = cli.Command{ dbImportCmd = &cli.Command{
Action: utils.MigrateFlags(importLDBdata), Action: importLDBdata,
Name: "import", Name: "import",
Usage: "Imports leveldb-data from an exported RLP dump.", Usage: "Imports leveldb-data from an exported RLP dump.",
ArgsUsage: "<dumpfile> <start (optional)", ArgsUsage: "<dumpfile> <start (optional)",
@ -178,8 +176,8 @@ WARNING: This is a low-level operation which may cause database corruption!`,
}, utils.NetworkFlags, utils.DatabasePathFlags), }, utils.NetworkFlags, utils.DatabasePathFlags),
Description: "The import command imports the specific chain data from an RLP encoded stream.", Description: "The import command imports the specific chain data from an RLP encoded stream.",
} }
dbExportCmd = cli.Command{ dbExportCmd = &cli.Command{
Action: utils.MigrateFlags(exportChaindata), Action: exportChaindata,
Name: "export", Name: "export",
Usage: "Exports the chain data into an RLP dump. If the <dumpfile> has .gz suffix, gzip compression will be used.", Usage: "Exports the chain data into an RLP dump. If the <dumpfile> has .gz suffix, gzip compression will be used.",
ArgsUsage: "<type> <dumpfile>", ArgsUsage: "<type> <dumpfile>",
@ -188,8 +186,8 @@ WARNING: This is a low-level operation which may cause database corruption!`,
}, utils.NetworkFlags, utils.DatabasePathFlags), }, utils.NetworkFlags, utils.DatabasePathFlags),
Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.", Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.",
} }
dbMetadataCmd = cli.Command{ dbMetadataCmd = &cli.Command{
Action: utils.MigrateFlags(showMetaData), Action: showMetaData,
Name: "metadata", Name: "metadata",
Usage: "Shows metadata about the chain status.", Usage: "Shows metadata about the chain status.",
Flags: utils.GroupFlags([]cli.Flag{ Flags: utils.GroupFlags([]cli.Flag{
@ -197,8 +195,8 @@ WARNING: This is a low-level operation which may cause database corruption!`,
}, utils.NetworkFlags, utils.DatabasePathFlags), }, utils.NetworkFlags, utils.DatabasePathFlags),
Description: "Shows metadata about the chain status.", Description: "Shows metadata about the chain status.",
} }
dbMigrateFreezerCmd = cli.Command{ dbMigrateFreezerCmd = &cli.Command{
Action: utils.MigrateFlags(freezerMigrate), Action: freezerMigrate,
Name: "freezer-migrate", Name: "freezer-migrate",
Usage: "Migrate legacy parts of the freezer. (WARNING: may take a long time)", Usage: "Migrate legacy parts of the freezer. (WARNING: may take a long time)",
ArgsUsage: "", ArgsUsage: "",

View File

@ -144,7 +144,7 @@ func initGeth(t *testing.T) string {
func startLightServer(t *testing.T) *gethrpc { func startLightServer(t *testing.T) *gethrpc {
datadir := initGeth(t) datadir := initGeth(t)
t.Logf("Importing keys to geth") t.Logf("Importing keys to geth")
runGeth(t, "--datadir", datadir, "--password", "./testdata/password.txt", "account", "import", "./testdata/key.prv", "--lightkdf").WaitExit() runGeth(t, "account", "import", "--datadir", datadir, "--password", "./testdata/password.txt", "--lightkdf", "./testdata/key.prv").WaitExit()
account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105" account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105"
server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1", "--verbosity=4") server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1", "--verbosity=4")
return server return server

View File

@ -44,7 +44,7 @@ import (
_ "github.com/ethereum/go-ethereum/eth/tracers/js" _ "github.com/ethereum/go-ethereum/eth/tracers/js"
_ "github.com/ethereum/go-ethereum/eth/tracers/native" _ "github.com/ethereum/go-ethereum/eth/tracers/native"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
const ( const (
@ -208,7 +208,7 @@ func init() {
app.Action = geth app.Action = geth
app.HideVersion = true // we have a command to print the version app.HideVersion = true // we have a command to print the version
app.Copyright = "Copyright 2013-2022 The go-ethereum Authors" app.Copyright = "Copyright 2013-2022 The go-ethereum Authors"
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
// See chaincmd.go: // See chaincmd.go:
initCommand, initCommand,
importCommand, importCommand,
@ -242,13 +242,16 @@ func init() {
} }
sort.Sort(cli.CommandsByName(app.Commands)) sort.Sort(cli.CommandsByName(app.Commands))
app.Flags = utils.GroupFlags(nodeFlags, app.Flags = utils.GroupFlags(
nodeFlags,
rpcFlags, rpcFlags,
consoleFlags, consoleFlags,
debug.Flags, debug.Flags,
metricsFlags) metricsFlags,
)
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
flags.MigrateGlobalFlags(ctx)
return debug.Setup(ctx) return debug.Setup(ctx)
} }
app.After = func(ctx *cli.Context) error { app.After = func(ctx *cli.Context) error {
@ -270,22 +273,22 @@ func main() {
func prepare(ctx *cli.Context) { func prepare(ctx *cli.Context) {
// If we're running a known preset, log it for convenience. // If we're running a known preset, log it for convenience.
switch { switch {
case ctx.GlobalIsSet(utils.RopstenFlag.Name): case ctx.IsSet(utils.RopstenFlag.Name):
log.Info("Starting Geth on Ropsten testnet...") log.Info("Starting Geth on Ropsten testnet...")
case ctx.GlobalIsSet(utils.RinkebyFlag.Name): case ctx.IsSet(utils.RinkebyFlag.Name):
log.Info("Starting Geth on Rinkeby testnet...") log.Info("Starting Geth on Rinkeby testnet...")
case ctx.GlobalIsSet(utils.GoerliFlag.Name): case ctx.IsSet(utils.GoerliFlag.Name):
log.Info("Starting Geth on Görli testnet...") log.Info("Starting Geth on Görli testnet...")
case ctx.GlobalIsSet(utils.SepoliaFlag.Name): case ctx.IsSet(utils.SepoliaFlag.Name):
log.Info("Starting Geth on Sepolia testnet...") log.Info("Starting Geth on Sepolia testnet...")
case ctx.GlobalIsSet(utils.KilnFlag.Name): case ctx.IsSet(utils.KilnFlag.Name):
log.Info("Starting Geth on Kiln testnet...") log.Info("Starting Geth on Kiln testnet...")
case ctx.GlobalIsSet(utils.DeveloperFlag.Name): case ctx.IsSet(utils.DeveloperFlag.Name):
log.Info("Starting Geth in ephemeral dev mode...") log.Info("Starting Geth in ephemeral dev mode...")
log.Warn(`You are running Geth in --dev mode. Please note the following: log.Warn(`You are running Geth in --dev mode. Please note the following:
@ -303,27 +306,27 @@ func prepare(ctx *cli.Context) {
to 0, and discovery is disabled. to 0, and discovery is disabled.
`) `)
case !ctx.GlobalIsSet(utils.NetworkIdFlag.Name): case !ctx.IsSet(utils.NetworkIdFlag.Name):
log.Info("Starting Geth on Ethereum mainnet...") log.Info("Starting Geth on Ethereum mainnet...")
} }
// If we're a full node on mainnet without --cache specified, bump default cache allowance // If we're a full node on mainnet without --cache specified, bump default cache allowance
if ctx.GlobalString(utils.SyncModeFlag.Name) != "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) && !ctx.GlobalIsSet(utils.NetworkIdFlag.Name) { if ctx.String(utils.SyncModeFlag.Name) != "light" && !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
// Make sure we're not on any supported preconfigured testnet either // Make sure we're not on any supported preconfigured testnet either
if !ctx.GlobalIsSet(utils.RopstenFlag.Name) && if !ctx.IsSet(utils.RopstenFlag.Name) &&
!ctx.GlobalIsSet(utils.SepoliaFlag.Name) && !ctx.IsSet(utils.SepoliaFlag.Name) &&
!ctx.GlobalIsSet(utils.RinkebyFlag.Name) && !ctx.IsSet(utils.RinkebyFlag.Name) &&
!ctx.GlobalIsSet(utils.GoerliFlag.Name) && !ctx.IsSet(utils.GoerliFlag.Name) &&
!ctx.GlobalIsSet(utils.KilnFlag.Name) && !ctx.IsSet(utils.KilnFlag.Name) &&
!ctx.GlobalIsSet(utils.DeveloperFlag.Name) { !ctx.IsSet(utils.DeveloperFlag.Name) {
// Nope, we're really on mainnet. Bump that cache up! // Nope, we're really on mainnet. Bump that cache up!
log.Info("Bumping default cache on mainnet", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 4096) log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(4096)) ctx.Set(utils.CacheFlag.Name, strconv.Itoa(4096))
} }
} }
// If we're running a light client on any network, drop the cache to some meaningfully low amount // If we're running a light client on any network, drop the cache to some meaningfully low amount
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" && !ctx.GlobalIsSet(utils.CacheFlag.Name) { if ctx.String(utils.SyncModeFlag.Name) == "light" && !ctx.IsSet(utils.CacheFlag.Name) {
log.Info("Dropping default light client cache", "provided", ctx.GlobalInt(utils.CacheFlag.Name), "updated", 128) log.Info("Dropping default light client cache", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 128)
ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(128)) ctx.Set(utils.CacheFlag.Name, strconv.Itoa(128))
} }
// Start metrics export if enabled // Start metrics export if enabled
@ -337,7 +340,7 @@ func prepare(ctx *cli.Context) {
// It creates a default node based on the command line arguments and runs it in // It creates a default node based on the command line arguments and runs it in
// blocking mode, waiting for it to be shut down. // blocking mode, waiting for it to be shut down.
func geth(ctx *cli.Context) error { func geth(ctx *cli.Context) error {
if args := ctx.Args(); len(args) > 0 { if args := ctx.Args().Slice(); len(args) > 0 {
return fmt.Errorf("invalid command: %q", args[0]) return fmt.Errorf("invalid command: %q", args[0])
} }
@ -408,7 +411,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
// Spawn a standalone goroutine for status synchronization monitoring, // Spawn a standalone goroutine for status synchronization monitoring,
// close the node when synchronization is complete if user required. // close the node when synchronization is complete if user required.
if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) { if ctx.Bool(utils.ExitWhenSyncedFlag.Name) {
go func() { go func() {
sub := stack.EventMux().Subscribe(downloader.DoneEvent{}) sub := stack.EventMux().Subscribe(downloader.DoneEvent{})
defer sub.Unsubscribe() defer sub.Unsubscribe()
@ -431,9 +434,9 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
} }
// Start auxiliary services if enabled // Start auxiliary services if enabled
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) { if ctx.Bool(utils.MiningEnabledFlag.Name) || ctx.Bool(utils.DeveloperFlag.Name) {
// Mining only makes sense if a full Ethereum node is running // Mining only makes sense if a full Ethereum node is running
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { if ctx.String(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining") utils.Fatalf("Light clients do not support mining")
} }
ethBackend, ok := backend.(*eth.EthAPIBackend) ethBackend, ok := backend.(*eth.EthAPIBackend)
@ -441,10 +444,10 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
utils.Fatalf("Ethereum service not running") utils.Fatalf("Ethereum service not running")
} }
// Set the gas price to the limits from the CLI and start mining // Set the gas price to the limits from the CLI and start mining
gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
ethBackend.TxPool().SetGasPrice(gasprice) ethBackend.TxPool().SetGasPrice(gasprice)
// start mining // start mining
threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name) threads := ctx.Int(utils.MinerThreadsFlag.Name)
if err := ethBackend.StartMining(threads); err != nil { if err := ethBackend.StartMining(threads); err != nil {
utils.Fatalf("Failed to start mining: %v", err) utils.Fatalf("Failed to start mining: %v", err)
} }
@ -454,7 +457,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
// unlockAccounts unlocks any account specifically requested. // unlockAccounts unlocks any account specifically requested.
func unlockAccounts(ctx *cli.Context, stack *node.Node) { func unlockAccounts(ctx *cli.Context, stack *node.Node) {
var unlocks []string var unlocks []string
inputs := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") inputs := strings.Split(ctx.String(utils.UnlockedAccountFlag.Name), ",")
for _, input := range inputs { for _, input := range inputs {
if trimmed := strings.TrimSpace(input); trimmed != "" { if trimmed := strings.TrimSpace(input); trimmed != "" {
unlocks = append(unlocks, trimmed) unlocks = append(unlocks, trimmed)

View File

@ -26,28 +26,27 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var ( var (
VersionCheckUrlFlag = cli.StringFlag{ VersionCheckUrlFlag = &cli.StringFlag{
Name: "check.url", Name: "check.url",
Usage: "URL to use when checking vulnerabilities", Usage: "URL to use when checking vulnerabilities",
Value: "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json", Value: "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json",
} }
VersionCheckVersionFlag = cli.StringFlag{ VersionCheckVersionFlag = &cli.StringFlag{
Name: "check.version", Name: "check.version",
Usage: "Version to check", Usage: "Version to check",
Value: fmt.Sprintf("Geth/v%v/%v-%v/%v", Value: fmt.Sprintf("Geth/v%v/%v-%v/%v",
params.VersionWithCommit(gitCommit, gitDate), params.VersionWithCommit(gitCommit, gitDate),
runtime.GOOS, runtime.GOARCH, runtime.Version()), runtime.GOOS, runtime.GOARCH, runtime.Version()),
} }
makecacheCommand = cli.Command{ makecacheCommand = &cli.Command{
Action: utils.MigrateFlags(makecache), Action: makecache,
Name: "makecache", Name: "makecache",
Usage: "Generate ethash verification cache (for testing)", Usage: "Generate ethash verification cache (for testing)",
ArgsUsage: "<blockNum> <outputDir>", ArgsUsage: "<blockNum> <outputDir>",
Category: "MISCELLANEOUS COMMANDS",
Description: ` Description: `
The makecache command generates an ethash cache in <outputDir>. The makecache command generates an ethash cache in <outputDir>.
@ -55,12 +54,11 @@ This command exists to support the system testing project.
Regular users do not need to execute it. Regular users do not need to execute it.
`, `,
} }
makedagCommand = cli.Command{ makedagCommand = &cli.Command{
Action: utils.MigrateFlags(makedag), Action: makedag,
Name: "makedag", Name: "makedag",
Usage: "Generate ethash mining DAG (for testing)", Usage: "Generate ethash mining DAG (for testing)",
ArgsUsage: "<blockNum> <outputDir>", ArgsUsage: "<blockNum> <outputDir>",
Category: "MISCELLANEOUS COMMANDS",
Description: ` Description: `
The makedag command generates an ethash DAG in <outputDir>. The makedag command generates an ethash DAG in <outputDir>.
@ -68,43 +66,40 @@ This command exists to support the system testing project.
Regular users do not need to execute it. Regular users do not need to execute it.
`, `,
} }
versionCommand = cli.Command{ versionCommand = &cli.Command{
Action: utils.MigrateFlags(version), Action: version,
Name: "version", Name: "version",
Usage: "Print version numbers", Usage: "Print version numbers",
ArgsUsage: " ", ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
Description: ` Description: `
The output of this command is supposed to be machine-readable. The output of this command is supposed to be machine-readable.
`, `,
} }
versionCheckCommand = cli.Command{ versionCheckCommand = &cli.Command{
Action: utils.MigrateFlags(versionCheck), Action: versionCheck,
Flags: []cli.Flag{ Flags: []cli.Flag{
VersionCheckUrlFlag, VersionCheckUrlFlag,
VersionCheckVersionFlag, VersionCheckVersionFlag,
}, },
Name: "version-check", Name: "version-check",
Usage: "Checks (online) whether the current version suffers from any known security vulnerabilities", Usage: "Checks (online) for known Geth security vulnerabilities",
ArgsUsage: "<versionstring (optional)>", ArgsUsage: "<versionstring (optional)>",
Category: "MISCELLANEOUS COMMANDS",
Description: ` Description: `
The version-check command fetches vulnerability-information from https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json, The version-check command fetches vulnerability-information from https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json,
and displays information about any security vulnerabilities that affect the currently executing version. and displays information about any security vulnerabilities that affect the currently executing version.
`, `,
} }
licenseCommand = cli.Command{ licenseCommand = &cli.Command{
Action: utils.MigrateFlags(license), Action: license,
Name: "license", Name: "license",
Usage: "Display license information", Usage: "Display license information",
ArgsUsage: " ", ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
} }
) )
// makecache generates an ethash verification cache into the provided folder. // makecache generates an ethash verification cache into the provided folder.
func makecache(ctx *cli.Context) error { func makecache(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args().Slice()
if len(args) != 2 { if len(args) != 2 {
utils.Fatalf(`Usage: geth makecache <block number> <outputdir>`) utils.Fatalf(`Usage: geth makecache <block number> <outputdir>`)
} }
@ -119,7 +114,7 @@ func makecache(ctx *cli.Context) error {
// makedag generates an ethash mining DAG into the provided folder. // makedag generates an ethash mining DAG into the provided folder.
func makedag(ctx *cli.Context) error { func makedag(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args().Slice()
if len(args) != 2 { if len(args) != 2 {
utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`) utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`)
} }

View File

@ -34,7 +34,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
cli "gopkg.in/urfave/cli.v1" cli "github.com/urfave/cli/v2"
) )
var ( var (
@ -46,18 +46,16 @@ var (
) )
var ( var (
snapshotCommand = cli.Command{ snapshotCommand = &cli.Command{
Name: "snapshot", Name: "snapshot",
Usage: "A set of commands based on the snapshot", Usage: "A set of commands based on the snapshot",
Category: "MISCELLANEOUS COMMANDS",
Description: "", Description: "",
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "prune-state", Name: "prune-state",
Usage: "Prune stale ethereum state data based on the snapshot", Usage: "Prune stale ethereum state data based on the snapshot",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: utils.MigrateFlags(pruneState), Action: pruneState,
Category: "MISCELLANEOUS COMMANDS",
Flags: utils.GroupFlags([]cli.Flag{ Flags: utils.GroupFlags([]cli.Flag{
utils.CacheTrieJournalFlag, utils.CacheTrieJournalFlag,
utils.BloomFilterSizeFlag, utils.BloomFilterSizeFlag,
@ -81,8 +79,7 @@ the trie clean cache with default directory will be deleted.
Name: "verify-state", Name: "verify-state",
Usage: "Recalculate state hash based on the snapshot for verification", Usage: "Recalculate state hash based on the snapshot for verification",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: utils.MigrateFlags(verifyState), Action: verifyState,
Category: "MISCELLANEOUS COMMANDS",
Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags),
Description: ` Description: `
geth snapshot verify-state <state-root> geth snapshot verify-state <state-root>
@ -95,8 +92,7 @@ In other words, this command does the snapshot to trie conversion.
Name: "check-dangling-storage", Name: "check-dangling-storage",
Usage: "Check that there is no 'dangling' snap storage", Usage: "Check that there is no 'dangling' snap storage",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: utils.MigrateFlags(checkDanglingStorage), Action: checkDanglingStorage,
Category: "MISCELLANEOUS COMMANDS",
Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags),
Description: ` Description: `
geth snapshot check-dangling-storage <state-root> traverses the snap storage geth snapshot check-dangling-storage <state-root> traverses the snap storage
@ -107,8 +103,7 @@ data, and verifies that all snapshot storage data has a corresponding account.
Name: "inspect-account", Name: "inspect-account",
Usage: "Check all snapshot layers for the a specific account", Usage: "Check all snapshot layers for the a specific account",
ArgsUsage: "<address | hash>", ArgsUsage: "<address | hash>",
Action: utils.MigrateFlags(checkAccount), Action: checkAccount,
Category: "MISCELLANEOUS COMMANDS",
Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags),
Description: ` Description: `
geth snapshot inspect-account <address | hash> checks all snapshot layers and prints out geth snapshot inspect-account <address | hash> checks all snapshot layers and prints out
@ -119,8 +114,7 @@ information about the specified address.
Name: "traverse-state", Name: "traverse-state",
Usage: "Traverse the state with given root hash and perform quick verification", Usage: "Traverse the state with given root hash and perform quick verification",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: utils.MigrateFlags(traverseState), Action: traverseState,
Category: "MISCELLANEOUS COMMANDS",
Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags),
Description: ` Description: `
geth snapshot traverse-state <state-root> geth snapshot traverse-state <state-root>
@ -135,8 +129,7 @@ It's also usable without snapshot enabled.
Name: "traverse-rawstate", Name: "traverse-rawstate",
Usage: "Traverse the state with given root hash and perform detailed verification", Usage: "Traverse the state with given root hash and perform detailed verification",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: utils.MigrateFlags(traverseRawState), Action: traverseRawState,
Category: "MISCELLANEOUS COMMANDS",
Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags), Flags: utils.GroupFlags(utils.NetworkFlags, utils.DatabasePathFlags),
Description: ` Description: `
geth snapshot traverse-rawstate <state-root> geth snapshot traverse-rawstate <state-root>
@ -152,8 +145,7 @@ It's also usable without snapshot enabled.
Name: "dump", Name: "dump",
Usage: "Dump a specific block from storage (same as 'geth dump' but using snapshots)", Usage: "Dump a specific block from storage (same as 'geth dump' but using snapshots)",
ArgsUsage: "[? <blockHash> | <blockNum>]", ArgsUsage: "[? <blockHash> | <blockNum>]",
Action: utils.MigrateFlags(dumpState), Action: dumpState,
Category: "MISCELLANEOUS COMMANDS",
Flags: utils.GroupFlags([]cli.Flag{ Flags: utils.GroupFlags([]cli.Flag{
utils.ExcludeCodeFlag, utils.ExcludeCodeFlag,
utils.ExcludeStorageFlag, utils.ExcludeStorageFlag,
@ -177,7 +169,7 @@ func pruneState(ctx *cli.Context) error {
defer stack.Close() defer stack.Close()
chaindb := utils.MakeChainDatabase(ctx, stack, false) chaindb := utils.MakeChainDatabase(ctx, stack, false)
pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name)) pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.Uint64(utils.BloomFilterSizeFlag.Name))
if err != nil { if err != nil {
log.Error("Failed to open snapshot tree", "err", err) log.Error("Failed to open snapshot tree", "err", err)
return err return err
@ -188,7 +180,7 @@ func pruneState(ctx *cli.Context) error {
} }
var targetRoot common.Hash var targetRoot common.Hash
if ctx.NArg() == 1 { if ctx.NArg() == 1 {
targetRoot, err = parseRoot(ctx.Args()[0]) targetRoot, err = parseRoot(ctx.Args().First())
if err != nil { if err != nil {
log.Error("Failed to resolve state root", "err", err) log.Error("Failed to resolve state root", "err", err)
return err return err
@ -222,7 +214,7 @@ func verifyState(ctx *cli.Context) error {
} }
var root = headBlock.Root() var root = headBlock.Root()
if ctx.NArg() == 1 { if ctx.NArg() == 1 {
root, err = parseRoot(ctx.Args()[0]) root, err = parseRoot(ctx.Args().First())
if err != nil { if err != nil {
log.Error("Failed to resolve state root", "err", err) log.Error("Failed to resolve state root", "err", err)
return err return err
@ -267,7 +259,7 @@ func traverseState(ctx *cli.Context) error {
err error err error
) )
if ctx.NArg() == 1 { if ctx.NArg() == 1 {
root, err = parseRoot(ctx.Args()[0]) root, err = parseRoot(ctx.Args().First())
if err != nil { if err != nil {
log.Error("Failed to resolve state root", "err", err) log.Error("Failed to resolve state root", "err", err)
return err return err
@ -356,7 +348,7 @@ func traverseRawState(ctx *cli.Context) error {
err error err error
) )
if ctx.NArg() == 1 { if ctx.NArg() == 1 {
root, err = parseRoot(ctx.Args()[0]) root, err = parseRoot(ctx.Args().First())
if err != nil { if err != nil {
log.Error("Failed to resolve state root", "err", err) log.Error("Failed to resolve state root", "err", err)
return err return err
@ -558,12 +550,12 @@ func checkAccount(ctx *cli.Context) error {
hash common.Hash hash common.Hash
addr common.Address addr common.Address
) )
switch len(ctx.Args()[0]) { switch arg := ctx.Args().First(); len(arg) {
case 40, 42: case 40, 42:
addr = common.HexToAddress(ctx.Args()[0]) addr = common.HexToAddress(arg)
hash = crypto.Keccak256Hash(addr.Bytes()) hash = crypto.Keccak256Hash(addr.Bytes())
case 64, 66: case 64, 66:
hash = common.HexToHash(ctx.Args()[0]) hash = common.HexToHash(arg)
default: default:
return errors.New("malformed address or hash") return errors.New("malformed address or hash")
} }

View File

@ -1,301 +0,0 @@
// 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"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/internal/flags"
"gopkg.in/urfave/cli.v1"
)
// AppHelpFlagGroups is the application flags, grouped by functionality.
var AppHelpFlagGroups = []flags.FlagGroup{
{
Name: "ETHEREUM",
Flags: utils.GroupFlags([]cli.Flag{
configFileFlag,
utils.MinFreeDiskSpaceFlag,
utils.KeyStoreDirFlag,
utils.USBFlag,
utils.SmartCardDaemonPathFlag,
utils.NetworkIdFlag,
utils.SyncModeFlag,
utils.ExitWhenSyncedFlag,
utils.GCModeFlag,
utils.TxLookupLimitFlag,
utils.EthStatsURLFlag,
utils.IdentityFlag,
utils.LightKDFFlag,
utils.EthRequiredBlocksFlag,
}, utils.NetworkFlags, utils.DatabasePathFlags),
},
{
Name: "LIGHT CLIENT",
Flags: []cli.Flag{
utils.LightServeFlag,
utils.LightIngressFlag,
utils.LightEgressFlag,
utils.LightMaxPeersFlag,
utils.UltraLightServersFlag,
utils.UltraLightFractionFlag,
utils.UltraLightOnlyAnnounceFlag,
utils.LightNoPruneFlag,
utils.LightNoSyncServeFlag,
},
},
{
Name: "DEVELOPER CHAIN",
Flags: []cli.Flag{
utils.DeveloperFlag,
utils.DeveloperPeriodFlag,
utils.DeveloperGasLimitFlag,
},
},
{
Name: "ETHASH",
Flags: []cli.Flag{
utils.EthashCacheDirFlag,
utils.EthashCachesInMemoryFlag,
utils.EthashCachesOnDiskFlag,
utils.EthashCachesLockMmapFlag,
utils.EthashDatasetDirFlag,
utils.EthashDatasetsInMemoryFlag,
utils.EthashDatasetsOnDiskFlag,
utils.EthashDatasetsLockMmapFlag,
},
},
{
Name: "TRANSACTION POOL",
Flags: []cli.Flag{
utils.TxPoolLocalsFlag,
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.CacheTrieFlag,
utils.CacheTrieJournalFlag,
utils.CacheTrieRejournalFlag,
utils.CacheGCFlag,
utils.CacheSnapshotFlag,
utils.CacheNoPrefetchFlag,
utils.CachePreimagesFlag,
utils.FDLimitFlag,
},
},
{
Name: "ACCOUNT",
Flags: []cli.Flag{
utils.UnlockedAccountFlag,
utils.PasswordFileFlag,
utils.ExternalSignerFlag,
utils.InsecureUnlockAllowedFlag,
},
},
{
Name: "API AND CONSOLE",
Flags: []cli.Flag{
utils.IPCDisabledFlag,
utils.IPCPathFlag,
utils.HTTPEnabledFlag,
utils.HTTPListenAddrFlag,
utils.HTTPPortFlag,
utils.HTTPApiFlag,
utils.HTTPPathPrefixFlag,
utils.HTTPCORSDomainFlag,
utils.HTTPVirtualHostsFlag,
utils.WSEnabledFlag,
utils.WSListenAddrFlag,
utils.WSPortFlag,
utils.WSApiFlag,
utils.WSPathPrefixFlag,
utils.WSAllowedOriginsFlag,
utils.JWTSecretFlag,
utils.AuthListenFlag,
utils.AuthPortFlag,
utils.AuthVirtualHostsFlag,
utils.GraphQLEnabledFlag,
utils.GraphQLCORSDomainFlag,
utils.GraphQLVirtualHostsFlag,
utils.RPCGlobalGasCapFlag,
utils.RPCGlobalEVMTimeoutFlag,
utils.RPCGlobalTxFeeCapFlag,
utils.AllowUnprotectedTxs,
utils.JSpathFlag,
utils.ExecFlag,
utils.PreloadJSFlag,
},
},
{
Name: "NETWORKING",
Flags: []cli.Flag{
utils.BootnodesFlag,
utils.DNSDiscoveryFlag,
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.MinerNotifyFlag,
utils.MinerNotifyFullFlag,
utils.MinerGasPriceFlag,
utils.MinerGasLimitFlag,
utils.MinerEtherbaseFlag,
utils.MinerExtraDataFlag,
utils.MinerRecommitIntervalFlag,
utils.MinerNoVerifyFlag,
},
},
{
Name: "GAS PRICE ORACLE",
Flags: []cli.Flag{
utils.GpoBlocksFlag,
utils.GpoPercentileFlag,
utils.GpoMaxGasPriceFlag,
utils.GpoIgnoreGasPriceFlag,
},
},
{
Name: "VIRTUAL MACHINE",
Flags: []cli.Flag{
utils.VMEnableDebugFlag,
},
},
{
Name: "LOGGING AND DEBUGGING",
Flags: append([]cli.Flag{
utils.FakePoWFlag,
utils.NoCompactionFlag,
}, debug.Flags...),
},
{
Name: "METRICS AND STATS",
Flags: metricsFlags,
},
{
Name: "ALIASED (deprecated)",
Flags: []cli.Flag{
utils.NoUSBFlag,
utils.LegacyWhitelistFlag,
},
},
{
Name: "MISC",
Flags: []cli.Flag{
utils.SnapshotFlag,
utils.BloomFilterSizeFlag,
utils.IgnoreLegacyReceiptsFlag,
cli.HelpFlag,
},
},
}
func init() {
// Override the default app help template
cli.AppHelpTemplate = flags.AppHelpTemplate
// 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 == flags.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{}{}
}
}
deprecated := make(map[string]struct{})
for _, flag := range utils.DeprecatedFlags {
deprecated[flag.String()] = struct{}{}
}
// Only add uncategorized flags if they are not deprecated
var uncategorized []cli.Flag
for _, flag := range data.(*cli.App).Flags {
if _, ok := categorized[flag.String()]; !ok {
if _, ok := deprecated[flag.String()]; !ok {
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, flags.HelpData{App: data, FlagGroups: AppHelpFlagGroups})
} else if tmpl == flags.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[flags.FlagCategory(flag, AppHelpFlagGroups)] = append(categorized[flags.FlagCategory(flag, AppHelpFlagGroups)], flag)
}
}
// sort to get a stable ordering
sorted := make([]flags.FlagGroup, 0, len(categorized))
for cat, flgs := range categorized {
sorted = append(sorted, flags.FlagGroup{Name: cat, Flags: flgs})
}
sort.Sort(flags.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)
}
}
}

View File

@ -28,7 +28,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/jedisct1/go-minisign" "github.com/jedisct1/go-minisign"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var gethPubKeys []string = []string{ var gethPubKeys []string = []string{

View File

@ -46,71 +46,77 @@ import (
"text/tabwriter" "text/tabwriter"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/simulations" "github.com/ethereum/go-ethereum/p2p/simulations"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var client *simulations.Client var client *simulations.Client
var ( var (
// global command flags // global command flags
apiFlag = cli.StringFlag{ apiFlag = &cli.StringFlag{
Name: "api", Name: "api",
Value: "http://localhost:8888", Value: "http://localhost:8888",
Usage: "simulation API URL", Usage: "simulation API URL",
EnvVar: "P2PSIM_API_URL", EnvVars: []string{"P2PSIM_API_URL"},
} }
// events subcommand flags // events subcommand flags
currentFlag = cli.BoolFlag{ currentFlag = &cli.BoolFlag{
Name: "current", Name: "current",
Usage: "get existing nodes and conns first", Usage: "get existing nodes and conns first",
} }
filterFlag = cli.StringFlag{ filterFlag = &cli.StringFlag{
Name: "filter", Name: "filter",
Value: "", Value: "",
Usage: "message filter", Usage: "message filter",
} }
// node create subcommand flags // node create subcommand flags
nameFlag = cli.StringFlag{ nameFlag = &cli.StringFlag{
Name: "name", Name: "name",
Value: "", Value: "",
Usage: "node name", Usage: "node name",
} }
servicesFlag = cli.StringFlag{ servicesFlag = &cli.StringFlag{
Name: "services", Name: "services",
Value: "", Value: "",
Usage: "node services (comma separated)", Usage: "node services (comma separated)",
} }
keyFlag = cli.StringFlag{ keyFlag = &cli.StringFlag{
Name: "key", Name: "key",
Value: "", Value: "",
Usage: "node private key (hex encoded)", Usage: "node private key (hex encoded)",
} }
// node rpc subcommand flags // node rpc subcommand flags
subscribeFlag = cli.BoolFlag{ subscribeFlag = &cli.BoolFlag{
Name: "subscribe", Name: "subscribe",
Usage: "method is a subscription", Usage: "method is a subscription",
} }
) )
var (
// Git information set by linker when building with ci.go.
gitCommit string
gitDate string
)
func main() { func main() {
app := cli.NewApp() app := flags.NewApp(gitCommit, gitDate, "devp2p simulation command-line client")
app.Usage = "devp2p simulation command-line client"
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
apiFlag, apiFlag,
} }
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
client = simulations.NewClient(ctx.GlobalString(apiFlag.Name)) client = simulations.NewClient(ctx.String(apiFlag.Name))
return nil return nil
} }
app.Commands = []cli.Command{ app.Commands = []*cli.Command{
{ {
Name: "show", Name: "show",
Usage: "show network information", Usage: "show network information",
@ -139,7 +145,7 @@ func main() {
Name: "node", Name: "node",
Usage: "manage simulation nodes", Usage: "manage simulation nodes",
Action: listNodes, Action: listNodes,
Subcommands: []cli.Command{ Subcommands: []*cli.Command{
{ {
Name: "list", Name: "list",
Usage: "list nodes", Usage: "list nodes",
@ -204,7 +210,7 @@ func main() {
} }
func showNetwork(ctx *cli.Context) error { func showNetwork(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
network, err := client.GetNetwork() network, err := client.GetNetwork()
@ -219,7 +225,7 @@ func showNetwork(ctx *cli.Context) error {
} }
func streamNetwork(ctx *cli.Context) error { func streamNetwork(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
events := make(chan *simulations.Event) events := make(chan *simulations.Event)
@ -245,7 +251,7 @@ func streamNetwork(ctx *cli.Context) error {
} }
func createSnapshot(ctx *cli.Context) error { func createSnapshot(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
snap, err := client.CreateSnapshot() snap, err := client.CreateSnapshot()
@ -256,7 +262,7 @@ func createSnapshot(ctx *cli.Context) error {
} }
func loadSnapshot(ctx *cli.Context) error { func loadSnapshot(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
snap := &simulations.Snapshot{} snap := &simulations.Snapshot{}
@ -267,7 +273,7 @@ func loadSnapshot(ctx *cli.Context) error {
} }
func listNodes(ctx *cli.Context) error { func listNodes(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodes, err := client.GetNodes() nodes, err := client.GetNodes()
@ -292,7 +298,7 @@ func protocolList(node *p2p.NodeInfo) []string {
} }
func createNode(ctx *cli.Context) error { func createNode(ctx *cli.Context) error {
if len(ctx.Args()) != 0 { if ctx.NArg() != 0 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
config := adapters.RandomNodeConfig() config := adapters.RandomNodeConfig()
@ -317,11 +323,10 @@ func createNode(ctx *cli.Context) error {
} }
func showNode(ctx *cli.Context) error { func showNode(ctx *cli.Context) error {
args := ctx.Args() if ctx.NArg() != 1 {
if len(args) != 1 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := ctx.Args().First()
node, err := client.GetNode(nodeName) node, err := client.GetNode(nodeName)
if err != nil { if err != nil {
return err return err
@ -342,11 +347,10 @@ func showNode(ctx *cli.Context) error {
} }
func startNode(ctx *cli.Context) error { func startNode(ctx *cli.Context) error {
args := ctx.Args() if ctx.NArg() != 1 {
if len(args) != 1 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := ctx.Args().First()
if err := client.StartNode(nodeName); err != nil { if err := client.StartNode(nodeName); err != nil {
return err return err
} }
@ -355,11 +359,10 @@ func startNode(ctx *cli.Context) error {
} }
func stopNode(ctx *cli.Context) error { func stopNode(ctx *cli.Context) error {
args := ctx.Args() if ctx.NArg() != 1 {
if len(args) != 1 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := ctx.Args().First()
if err := client.StopNode(nodeName); err != nil { if err := client.StopNode(nodeName); err != nil {
return err return err
} }
@ -368,12 +371,12 @@ func stopNode(ctx *cli.Context) error {
} }
func connectNode(ctx *cli.Context) error { func connectNode(ctx *cli.Context) error {
args := ctx.Args() if ctx.NArg() != 2 {
if len(args) != 2 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] args := ctx.Args()
peerName := args[1] nodeName := args.Get(0)
peerName := args.Get(1)
if err := client.ConnectNode(nodeName, peerName); err != nil { if err := client.ConnectNode(nodeName, peerName); err != nil {
return err return err
} }
@ -383,11 +386,11 @@ func connectNode(ctx *cli.Context) error {
func disconnectNode(ctx *cli.Context) error { func disconnectNode(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args()
if len(args) != 2 { if args.Len() != 2 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := args.Get(0)
peerName := args[1] peerName := args.Get(1)
if err := client.DisconnectNode(nodeName, peerName); err != nil { if err := client.DisconnectNode(nodeName, peerName); err != nil {
return err return err
} }
@ -397,21 +400,21 @@ func disconnectNode(ctx *cli.Context) error {
func rpcNode(ctx *cli.Context) error { func rpcNode(ctx *cli.Context) error {
args := ctx.Args() args := ctx.Args()
if len(args) < 2 { if args.Len() < 2 {
return cli.ShowCommandHelp(ctx, ctx.Command.Name) return cli.ShowCommandHelp(ctx, ctx.Command.Name)
} }
nodeName := args[0] nodeName := args.Get(0)
method := args[1] method := args.Get(1)
rpcClient, err := client.RPCClient(context.Background(), nodeName) rpcClient, err := client.RPCClient(context.Background(), nodeName)
if err != nil { if err != nil {
return err return err
} }
if ctx.Bool(subscribeFlag.Name) { if ctx.Bool(subscribeFlag.Name) {
return rpcSubscribe(rpcClient, ctx.App.Writer, method, args[3:]...) return rpcSubscribe(rpcClient, ctx.App.Writer, method, args.Slice()[3:]...)
} }
var result interface{} var result interface{}
params := make([]interface{}, len(args[3:])) params := make([]interface{}, len(args.Slice()[3:]))
for i, v := range args[3:] { for i, v := range args.Slice()[3:] {
params[i] = v params[i] = v
} }
if err := rpcClient.Call(&result, method, params...); err != nil { if err := rpcClient.Call(&result, method, params...); err != nil {

View File

@ -24,7 +24,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
// main is just a boring entry point to set up the CLI app. // main is just a boring entry point to set up the CLI app.
@ -33,11 +33,11 @@ func main() {
app.Name = "puppeth" app.Name = "puppeth"
app.Usage = "assemble and maintain private Ethereum networks" app.Usage = "assemble and maintain private Ethereum networks"
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.StringFlag{ &cli.StringFlag{
Name: "network", Name: "network",
Usage: "name of the network to administer (no spaces or hyphens, please)", Usage: "name of the network to administer (no spaces or hyphens, please)",
}, },
cli.IntFlag{ &cli.IntFlag{
Name: "loglevel", Name: "loglevel",
Value: 3, Value: 3,
Usage: "log level to emit to the screen", Usage: "log level to emit to the screen",

View File

@ -41,7 +41,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
const ( const (
@ -78,10 +78,10 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) {
defer signal.Stop(sigc) defer signal.Stop(sigc)
minFreeDiskSpace := 2 * ethconfig.Defaults.TrieDirtyCache // Default 2 * 256Mb minFreeDiskSpace := 2 * ethconfig.Defaults.TrieDirtyCache // Default 2 * 256Mb
if ctx.GlobalIsSet(MinFreeDiskSpaceFlag.Name) { if ctx.IsSet(MinFreeDiskSpaceFlag.Name) {
minFreeDiskSpace = ctx.GlobalInt(MinFreeDiskSpaceFlag.Name) minFreeDiskSpace = ctx.Int(MinFreeDiskSpaceFlag.Name)
} else if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { } else if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) {
minFreeDiskSpace = 2 * ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 minFreeDiskSpace = 2 * ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100
} }
if minFreeDiskSpace > 0 { if minFreeDiskSpace > 0 {
go monitorFreeDiskSpace(sigc, stack.InstanceDir(), uint64(minFreeDiskSpace)*1024*1024) go monitorFreeDiskSpace(sigc, stack.InstanceDir(), uint64(minFreeDiskSpace)*1024*1024)

View File

@ -1,211 +0,0 @@
// 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 utils
import (
"encoding"
"errors"
"flag"
"math/big"
"os"
"os/user"
"path"
"strings"
"github.com/ethereum/go-ethereum/common/math"
"gopkg.in/urfave/cli.v1"
)
// Custom type which is registered in the flags library which cli uses for
// argument parsing. This allows us to expand Value to an absolute path when
// the argument is parsed
type DirectoryString string
func (s *DirectoryString) String() string {
return string(*s)
}
func (s *DirectoryString) Set(value string) error {
*s = DirectoryString(expandPath(value))
return nil
}
// Custom cli.Flag type which expand the received string to an absolute path.
// e.g. ~/.ethereum -> /home/username/.ethereum
type DirectoryFlag struct {
Name string
Value DirectoryString
Usage string
EnvVar string
}
func (f DirectoryFlag) String() string {
return cli.FlagStringer(f)
}
// called by cli library, grabs variable from environment (if in env)
// and adds variable to flag set for parsing.
func (f DirectoryFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Var(&f.Value, f.Name, f.Usage)
})
}
func (f DirectoryFlag) GetName() string {
return f.Name
}
func (f *DirectoryFlag) Set(value string) {
f.Value.Set(value)
}
func eachName(longName string, fn func(string)) {
parts := strings.Split(longName, ",")
for _, name := range parts {
name = strings.Trim(name, " ")
fn(name)
}
}
type TextMarshaler interface {
encoding.TextMarshaler
encoding.TextUnmarshaler
}
// textMarshalerVal turns a TextMarshaler into a flag.Value
type textMarshalerVal struct {
v TextMarshaler
}
func (v textMarshalerVal) String() string {
if v.v == nil {
return ""
}
text, _ := v.v.MarshalText()
return string(text)
}
func (v textMarshalerVal) Set(s string) error {
return v.v.UnmarshalText([]byte(s))
}
// TextMarshalerFlag wraps a TextMarshaler value.
type TextMarshalerFlag struct {
Name string
Value TextMarshaler
Usage string
EnvVar string
}
func (f TextMarshalerFlag) GetName() string {
return f.Name
}
func (f TextMarshalerFlag) String() string {
return cli.FlagStringer(f)
}
func (f TextMarshalerFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage)
})
}
// GlobalTextMarshaler returns the value of a TextMarshalerFlag from the global flag set.
func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler {
val := ctx.GlobalGeneric(name)
if val == nil {
return nil
}
return val.(textMarshalerVal).v
}
// BigFlag is a command line flag that accepts 256 bit big integers in decimal or
// hexadecimal syntax.
type BigFlag struct {
Name string
Value *big.Int
Usage string
EnvVar string
}
// bigValue turns *big.Int into a flag.Value
type bigValue big.Int
func (b *bigValue) String() string {
if b == nil {
return ""
}
return (*big.Int)(b).String()
}
func (b *bigValue) Set(s string) error {
intVal, ok := math.ParseBig256(s)
if !ok {
return errors.New("invalid integer syntax")
}
*b = (bigValue)(*intVal)
return nil
}
func (f BigFlag) GetName() string {
return f.Name
}
func (f BigFlag) String() string {
return cli.FlagStringer(f)
}
func (f BigFlag) Apply(set *flag.FlagSet) {
eachName(f.Name, func(name string) {
f.Value = new(big.Int)
set.Var((*bigValue)(f.Value), f.Name, f.Usage)
})
}
// GlobalBig returns the value of a BigFlag from the global flag set.
func GlobalBig(ctx *cli.Context, name string) *big.Int {
val := ctx.GlobalGeneric(name)
if val == nil {
return nil
}
return (*big.Int)(val.(*bigValue))
}
// Expands a file path
// 1. replace tilde with users home dir
// 2. expands embedded environment variables
// 3. cleans the path, e.g. /a/b/../c -> /a/c
// Note, it has limitations, e.g. ~someuser/tmp will not be expanded
func expandPath(p string) string {
if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
if home := HomeDir(); home != "" {
p = home + p[1:]
}
}
return path.Clean(os.ExpandEnv(p))
}
func HomeDir() string {
if home := os.Getenv("HOME"); home != "" {
return home
}
if usr, err := user.Current(); err == nil {
return usr.HomeDir
}
return ""
}

File diff suppressed because it is too large Load Diff

View File

@ -20,15 +20,15 @@ import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/ethconfig"
"gopkg.in/urfave/cli.v1" "github.com/ethereum/go-ethereum/internal/flags"
"github.com/urfave/cli/v2"
) )
var ShowDeprecated = cli.Command{ var ShowDeprecated = &cli.Command{
Action: showDeprecated, Action: showDeprecated,
Name: "show-deprecated-flags", Name: "show-deprecated-flags",
Usage: "Show flags that have been deprecated", Usage: "Show flags that have been deprecated",
ArgsUsage: " ", ArgsUsage: " ",
Category: "MISCELLANEOUS COMMANDS",
Description: "Show flags that have been deprecated and will soon be removed", Description: "Show flags that have been deprecated and will soon be removed",
} }
@ -39,20 +39,22 @@ var DeprecatedFlags = []cli.Flag{
var ( var (
// (Deprecated May 2020, shown in aliased flags section) // (Deprecated May 2020, shown in aliased flags section)
NoUSBFlag = cli.BoolFlag{ NoUSBFlag = &cli.BoolFlag{
Name: "nousb", Name: "nousb",
Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)", Usage: "Disables monitoring for and managing USB hardware wallets (deprecated)",
Category: flags.DeprecatedCategory,
} }
// (Deprecated July 2021, shown in aliased flags section) // (Deprecated July 2021, shown in aliased flags section)
LegacyMinerGasTargetFlag = cli.Uint64Flag{ LegacyMinerGasTargetFlag = &cli.Uint64Flag{
Name: "miner.gastarget", Name: "miner.gastarget",
Usage: "Target gas floor for mined blocks (deprecated)", Usage: "Target gas floor for mined blocks (deprecated)",
Value: ethconfig.Defaults.Miner.GasFloor, Value: ethconfig.Defaults.Miner.GasFloor,
Category: flags.DeprecatedCategory,
} }
) )
// showDeprecated displays deprecated flags that will be soon removed from the codebase. // showDeprecated displays deprecated flags that will be soon removed from the codebase.
func showDeprecated(*cli.Context) { func showDeprecated(*cli.Context) error {
fmt.Println("--------------------------------------------------------------------") fmt.Println("--------------------------------------------------------------------")
fmt.Println("The following flags are deprecated and will be removed in the future!") fmt.Println("The following flags are deprecated and will be removed in the future!")
fmt.Println("--------------------------------------------------------------------") fmt.Println("--------------------------------------------------------------------")
@ -61,4 +63,5 @@ func showDeprecated(*cli.Context) {
fmt.Println(flag.String()) fmt.Println(flag.String())
} }
fmt.Println() fmt.Println()
return nil
} }

5
go.mod
View File

@ -55,6 +55,7 @@ require (
github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344 github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
github.com/urfave/cli/v2 v2.10.2
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
@ -64,7 +65,6 @@ require (
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
gopkg.in/urfave/cli.v1 v1.20.0
) )
require ( require (
@ -77,6 +77,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.1.1 // indirect
github.com/aws/smithy-go v1.1.0 // indirect github.com/aws/smithy-go v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
@ -92,8 +93,10 @@ require (
github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/opentracing/opentracing-go v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect github.com/tklauser/numcpus v0.2.2 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect
golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect

11
go.sum
View File

@ -25,6 +25,7 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 h1:Px2UA+2RvSSvv+RvJNuUB6n7rs5Wsel4dXLe90Um2n4=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -83,6 +84,8 @@ github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f h1:C43yEtQ6NIf4ftFXD/V55gnGFgPbMQobd//YlnLjUJ8=
github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
@ -371,6 +374,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
@ -408,11 +413,15 @@ github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZF
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y=
github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@ -662,8 +671,6 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -24,71 +24,84 @@ import (
"os" "os"
"runtime" "runtime"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/metrics/exp" "github.com/ethereum/go-ethereum/metrics/exp"
"github.com/fjl/memsize/memsizeui" "github.com/fjl/memsize/memsizeui"
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var Memsize memsizeui.Handler var Memsize memsizeui.Handler
var ( var (
verbosityFlag = cli.IntFlag{ verbosityFlag = &cli.IntFlag{
Name: "verbosity", Name: "verbosity",
Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail",
Value: 3, Value: 3,
Category: flags.LoggingCategory,
} }
vmoduleFlag = cli.StringFlag{ vmoduleFlag = &cli.StringFlag{
Name: "vmodule", Name: "vmodule",
Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)", Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)",
Value: "", Value: "",
Category: flags.LoggingCategory,
} }
logjsonFlag = cli.BoolFlag{ logjsonFlag = &cli.BoolFlag{
Name: "log.json", Name: "log.json",
Usage: "Format logs with JSON", Usage: "Format logs with JSON",
Category: flags.LoggingCategory,
} }
backtraceAtFlag = cli.StringFlag{ backtraceAtFlag = &cli.StringFlag{
Name: "log.backtrace", Name: "log.backtrace",
Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")", Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")",
Value: "", Value: "",
Category: flags.LoggingCategory,
} }
debugFlag = cli.BoolFlag{ debugFlag = &cli.BoolFlag{
Name: "log.debug", Name: "log.debug",
Usage: "Prepends log messages with call-site location (file and line number)", Usage: "Prepends log messages with call-site location (file and line number)",
Category: flags.LoggingCategory,
} }
pprofFlag = cli.BoolFlag{ pprofFlag = &cli.BoolFlag{
Name: "pprof", Name: "pprof",
Usage: "Enable the pprof HTTP server", Usage: "Enable the pprof HTTP server",
Category: flags.LoggingCategory,
} }
pprofPortFlag = cli.IntFlag{ pprofPortFlag = &cli.IntFlag{
Name: "pprof.port", Name: "pprof.port",
Usage: "pprof HTTP server listening port", Usage: "pprof HTTP server listening port",
Value: 6060, Value: 6060,
Category: flags.LoggingCategory,
} }
pprofAddrFlag = cli.StringFlag{ pprofAddrFlag = &cli.StringFlag{
Name: "pprof.addr", Name: "pprof.addr",
Usage: "pprof HTTP server listening interface", Usage: "pprof HTTP server listening interface",
Value: "127.0.0.1", Value: "127.0.0.1",
Category: flags.LoggingCategory,
} }
memprofilerateFlag = cli.IntFlag{ memprofilerateFlag = &cli.IntFlag{
Name: "pprof.memprofilerate", Name: "pprof.memprofilerate",
Usage: "Turn on memory profiling with the given rate", Usage: "Turn on memory profiling with the given rate",
Value: runtime.MemProfileRate, Value: runtime.MemProfileRate,
Category: flags.LoggingCategory,
} }
blockprofilerateFlag = cli.IntFlag{ blockprofilerateFlag = &cli.IntFlag{
Name: "pprof.blockprofilerate", Name: "pprof.blockprofilerate",
Usage: "Turn on block profiling with the given rate", Usage: "Turn on block profiling with the given rate",
Category: flags.LoggingCategory,
} }
cpuprofileFlag = cli.StringFlag{ cpuprofileFlag = &cli.StringFlag{
Name: "pprof.cpuprofile", Name: "pprof.cpuprofile",
Usage: "Write CPU profile to the given file", Usage: "Write CPU profile to the given file",
Category: flags.LoggingCategory,
} }
traceFlag = cli.StringFlag{ traceFlag = &cli.StringFlag{
Name: "trace", Name: "trace",
Usage: "Write execution trace to the given file", Usage: "Write execution trace to the given file",
Category: flags.LoggingCategory,
} }
) )
@ -121,7 +134,7 @@ func init() {
func Setup(ctx *cli.Context) error { func Setup(ctx *cli.Context) error {
var ostream log.Handler var ostream log.Handler
output := io.Writer(os.Stderr) output := io.Writer(os.Stderr)
if ctx.GlobalBool(logjsonFlag.Name) { if ctx.Bool(logjsonFlag.Name) {
ostream = log.StreamHandler(output, log.JSONFormat()) ostream = log.StreamHandler(output, log.JSONFormat())
} else { } else {
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
@ -133,53 +146,53 @@ func Setup(ctx *cli.Context) error {
glogger.SetHandler(ostream) glogger.SetHandler(ostream)
// logging // logging
verbosity := ctx.GlobalInt(verbosityFlag.Name) verbosity := ctx.Int(verbosityFlag.Name)
glogger.Verbosity(log.Lvl(verbosity)) glogger.Verbosity(log.Lvl(verbosity))
vmodule := ctx.GlobalString(vmoduleFlag.Name) vmodule := ctx.String(vmoduleFlag.Name)
glogger.Vmodule(vmodule) glogger.Vmodule(vmodule)
debug := ctx.GlobalBool(debugFlag.Name) debug := ctx.Bool(debugFlag.Name)
if ctx.GlobalIsSet(debugFlag.Name) { if ctx.IsSet(debugFlag.Name) {
debug = ctx.GlobalBool(debugFlag.Name) debug = ctx.Bool(debugFlag.Name)
} }
log.PrintOrigins(debug) log.PrintOrigins(debug)
backtrace := ctx.GlobalString(backtraceAtFlag.Name) backtrace := ctx.String(backtraceAtFlag.Name)
glogger.BacktraceAt(backtrace) glogger.BacktraceAt(backtrace)
log.Root().SetHandler(glogger) log.Root().SetHandler(glogger)
// profiling, tracing // profiling, tracing
runtime.MemProfileRate = memprofilerateFlag.Value runtime.MemProfileRate = memprofilerateFlag.Value
if ctx.GlobalIsSet(memprofilerateFlag.Name) { if ctx.IsSet(memprofilerateFlag.Name) {
runtime.MemProfileRate = ctx.GlobalInt(memprofilerateFlag.Name) runtime.MemProfileRate = ctx.Int(memprofilerateFlag.Name)
} }
blockProfileRate := ctx.GlobalInt(blockprofilerateFlag.Name) blockProfileRate := ctx.Int(blockprofilerateFlag.Name)
Handler.SetBlockProfileRate(blockProfileRate) Handler.SetBlockProfileRate(blockProfileRate)
if traceFile := ctx.GlobalString(traceFlag.Name); traceFile != "" { if traceFile := ctx.String(traceFlag.Name); traceFile != "" {
if err := Handler.StartGoTrace(traceFile); err != nil { if err := Handler.StartGoTrace(traceFile); err != nil {
return err return err
} }
} }
if cpuFile := ctx.GlobalString(cpuprofileFlag.Name); cpuFile != "" { if cpuFile := ctx.String(cpuprofileFlag.Name); cpuFile != "" {
if err := Handler.StartCPUProfile(cpuFile); err != nil { if err := Handler.StartCPUProfile(cpuFile); err != nil {
return err return err
} }
} }
// pprof server // pprof server
if ctx.GlobalBool(pprofFlag.Name) { if ctx.Bool(pprofFlag.Name) {
listenHost := ctx.GlobalString(pprofAddrFlag.Name) listenHost := ctx.String(pprofAddrFlag.Name)
port := ctx.GlobalInt(pprofPortFlag.Name) port := ctx.Int(pprofPortFlag.Name)
address := fmt.Sprintf("%s:%d", listenHost, port) address := fmt.Sprintf("%s:%d", listenHost, port)
// This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name. // This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name.
// It cannot be imported because it will cause a cyclical dependency. // It cannot be imported because it will cause a cyclical dependency.
StartPProf(address, !ctx.GlobalIsSet("metrics.addr")) StartPProf(address, !ctx.IsSet("metrics.addr"))
} }
return nil return nil
} }

View File

@ -0,0 +1,43 @@
// Copyright 2022 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 flags
import "github.com/urfave/cli/v2"
const (
EthCategory = "ETHEREUM"
LightCategory = "LIGHT CLIENT"
DevCategory = "DEVELOPER CHAIN"
EthashCategory = "ETHASH"
TxPoolCategory = "TRANSACTION POOL"
PerfCategory = "PERFORMANCE TUNING"
AccountCategory = "ACCOUNT"
APICategory = "API AND CONSOLE"
NetworkingCategory = "NETWORKING"
MinerCategory = "MINER"
GasPriceCategory = "GAS PRICE ORACLE"
VMCategory = "VIRTUAL MACHINE"
LoggingCategory = "LOGGING AND DEBUGGING"
MetricsCategory = "METRICS AND STATS"
MiscCategory = "MISC"
DeprecatedCategory = "ALIASED (deprecated)"
)
func init() {
cli.HelpFlag.(*cli.BoolFlag).Category = MiscCategory
cli.VersionFlag.(*cli.BoolFlag).Category = MiscCategory
}

340
internal/flags/flags.go Normal file
View File

@ -0,0 +1,340 @@
// Copyright 2015 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 flags
import (
"encoding"
"errors"
"flag"
"math/big"
"os"
"os/user"
"path"
"strings"
"github.com/ethereum/go-ethereum/common/math"
"github.com/urfave/cli/v2"
)
// DirectoryString is custom type which is registered in the flags library which cli uses for
// argument parsing. This allows us to expand Value to an absolute path when
// the argument is parsed
type DirectoryString string
func (s *DirectoryString) String() string {
return string(*s)
}
func (s *DirectoryString) Set(value string) error {
*s = DirectoryString(expandPath(value))
return nil
}
var (
_ cli.Flag = (*DirectoryFlag)(nil)
_ cli.RequiredFlag = (*DirectoryFlag)(nil)
_ cli.VisibleFlag = (*DirectoryFlag)(nil)
_ cli.DocGenerationFlag = (*DirectoryFlag)(nil)
_ cli.CategorizableFlag = (*DirectoryFlag)(nil)
)
// DirectoryFlag is custom cli.Flag type which expand the received string to an absolute path.
// e.g. ~/.ethereum -> /home/username/.ethereum
type DirectoryFlag struct {
Name string
Category string
DefaultText string
Usage string
Required bool
Hidden bool
HasBeenSet bool
Value DirectoryString
Aliases []string
}
// For cli.Flag:
func (f *DirectoryFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) }
func (f *DirectoryFlag) IsSet() bool { return f.HasBeenSet }
func (f *DirectoryFlag) String() string { return cli.FlagStringer(f) }
// Apply called by cli library, grabs variable from environment (if in env)
// and adds variable to flag set for parsing.
func (f *DirectoryFlag) Apply(set *flag.FlagSet) error {
eachName(f, func(name string) {
set.Var(&f.Value, f.Name, f.Usage)
})
return nil
}
// For cli.RequiredFlag:
func (f *DirectoryFlag) IsRequired() bool { return f.Required }
// For cli.VisibleFlag:
func (f *DirectoryFlag) IsVisible() bool { return !f.Hidden }
// For cli.CategorizableFlag:
func (f *DirectoryFlag) GetCategory() string { return f.Category }
// For cli.DocGenerationFlag:
func (f *DirectoryFlag) TakesValue() bool { return true }
func (f *DirectoryFlag) GetUsage() string { return f.Usage }
func (f *DirectoryFlag) GetValue() string { return f.Value.String() }
func (f *DirectoryFlag) GetEnvVars() []string { return nil } // env not supported
func (f *DirectoryFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
type TextMarshaler interface {
encoding.TextMarshaler
encoding.TextUnmarshaler
}
// textMarshalerVal turns a TextMarshaler into a flag.Value
type textMarshalerVal struct {
v TextMarshaler
}
func (v textMarshalerVal) String() string {
if v.v == nil {
return ""
}
text, _ := v.v.MarshalText()
return string(text)
}
func (v textMarshalerVal) Set(s string) error {
return v.v.UnmarshalText([]byte(s))
}
var (
_ cli.Flag = (*TextMarshalerFlag)(nil)
_ cli.RequiredFlag = (*TextMarshalerFlag)(nil)
_ cli.VisibleFlag = (*TextMarshalerFlag)(nil)
_ cli.DocGenerationFlag = (*TextMarshalerFlag)(nil)
_ cli.CategorizableFlag = (*TextMarshalerFlag)(nil)
)
// TextMarshalerFlag wraps a TextMarshaler value.
type TextMarshalerFlag struct {
Name string
Category string
DefaultText string
Usage string
Required bool
Hidden bool
HasBeenSet bool
Value TextMarshaler
Aliases []string
}
// For cli.Flag:
func (f *TextMarshalerFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) }
func (f *TextMarshalerFlag) IsSet() bool { return f.HasBeenSet }
func (f *TextMarshalerFlag) String() string { return cli.FlagStringer(f) }
func (f *TextMarshalerFlag) Apply(set *flag.FlagSet) error {
eachName(f, func(name string) {
set.Var(textMarshalerVal{f.Value}, f.Name, f.Usage)
})
return nil
}
// For cli.RequiredFlag:
func (f *TextMarshalerFlag) IsRequired() bool { return f.Required }
// For cli.VisibleFlag:
func (f *TextMarshalerFlag) IsVisible() bool { return !f.Hidden }
// For cli.CategorizableFlag:
func (f *TextMarshalerFlag) GetCategory() string { return f.Category }
// For cli.DocGenerationFlag:
func (f *TextMarshalerFlag) TakesValue() bool { return true }
func (f *TextMarshalerFlag) GetUsage() string { return f.Usage }
func (f *TextMarshalerFlag) GetEnvVars() []string { return nil } // env not supported
func (f *TextMarshalerFlag) GetValue() string {
t, err := f.Value.MarshalText()
if err != nil {
return "(ERR: " + err.Error() + ")"
}
return string(t)
}
func (f *TextMarshalerFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// GlobalTextMarshaler returns the value of a TextMarshalerFlag from the global flag set.
func GlobalTextMarshaler(ctx *cli.Context, name string) TextMarshaler {
val := ctx.Generic(name)
if val == nil {
return nil
}
return val.(textMarshalerVal).v
}
var (
_ cli.Flag = (*BigFlag)(nil)
_ cli.RequiredFlag = (*BigFlag)(nil)
_ cli.VisibleFlag = (*BigFlag)(nil)
_ cli.DocGenerationFlag = (*BigFlag)(nil)
_ cli.CategorizableFlag = (*BigFlag)(nil)
)
// BigFlag is a command line flag that accepts 256 bit big integers in decimal or
// hexadecimal syntax.
type BigFlag struct {
Name string
Category string
DefaultText string
Usage string
Required bool
Hidden bool
HasBeenSet bool
Value *big.Int
Aliases []string
}
// For cli.Flag:
func (f *BigFlag) Names() []string { return append([]string{f.Name}, f.Aliases...) }
func (f *BigFlag) IsSet() bool { return f.HasBeenSet }
func (f *BigFlag) String() string { return cli.FlagStringer(f) }
func (f *BigFlag) Apply(set *flag.FlagSet) error {
eachName(f, func(name string) {
f.Value = new(big.Int)
set.Var((*bigValue)(f.Value), f.Name, f.Usage)
})
return nil
}
// For cli.RequiredFlag:
func (f *BigFlag) IsRequired() bool { return f.Required }
// For cli.VisibleFlag:
func (f *BigFlag) IsVisible() bool { return !f.Hidden }
// For cli.CategorizableFlag:
func (f *BigFlag) GetCategory() string { return f.Category }
// For cli.DocGenerationFlag:
func (f *BigFlag) TakesValue() bool { return true }
func (f *BigFlag) GetUsage() string { return f.Usage }
func (f *BigFlag) GetValue() string { return f.Value.String() }
func (f *BigFlag) GetEnvVars() []string { return nil } // env not supported
func (f *BigFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// bigValue turns *big.Int into a flag.Value
type bigValue big.Int
func (b *bigValue) String() string {
if b == nil {
return ""
}
return (*big.Int)(b).String()
}
func (b *bigValue) Set(s string) error {
intVal, ok := math.ParseBig256(s)
if !ok {
return errors.New("invalid integer syntax")
}
*b = (bigValue)(*intVal)
return nil
}
// GlobalBig returns the value of a BigFlag from the global flag set.
func GlobalBig(ctx *cli.Context, name string) *big.Int {
val := ctx.Generic(name)
if val == nil {
return nil
}
return (*big.Int)(val.(*bigValue))
}
// Expands a file path
// 1. replace tilde with users home dir
// 2. expands embedded environment variables
// 3. cleans the path, e.g. /a/b/../c -> /a/c
// Note, it has limitations, e.g. ~someuser/tmp will not be expanded
func expandPath(p string) string {
if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") {
if home := HomeDir(); home != "" {
p = home + p[1:]
}
}
return path.Clean(os.ExpandEnv(p))
}
func HomeDir() string {
if home := os.Getenv("HOME"); home != "" {
return home
}
if usr, err := user.Current(); err == nil {
return usr.HomeDir
}
return ""
}
func eachName(f cli.Flag, fn func(string)) {
for _, name := range f.Names() {
name = strings.Trim(name, " ")
fn(name)
}
}

View File

@ -1,20 +1,20 @@
// Copyright 2015 The go-ethereum Authors // Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum. // This file is part of the go-ethereum library.
// //
// go-ethereum is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// go-ethereum is distributed in the hope that it will be useful, // The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU Lesser General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU Lesser General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package utils package flags
import ( import (
"os" "os"

View File

@ -17,137 +17,160 @@
package flags package flags
import ( import (
"os" "fmt"
"path/filepath" "strings"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"gopkg.in/urfave/cli.v1" "github.com/urfave/cli/v2"
) )
var (
CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} {{.cmd.ArgsUsage}}
{{if .cmd.Description}}{{.cmd.Description}}
{{end}}{{if .cmd.Subcommands}}
SUBCOMMANDS:
{{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
{{end}}{{end}}{{if .categorizedFlags}}
{{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
{{range $categorized.Flags}}{{"\t"}}{{.}}
{{end}}
{{end}}{{end}}`
OriginCommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} {{.ArgsUsage}}
{{if .Description}}{{.Description}}
{{end}}{{if .Subcommands}}
SUBCOMMANDS:
{{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
{{end}}{{end}}{{if .Flags}}
OPTIONS:
{{range $.Flags}} {{.}}
{{end}}
{{end}}`
// AppHelpTemplate is the test template for the default, global app help topic.
AppHelpTemplate = `NAME:
{{.App.Name}} - {{.App.Usage}}
Copyright 2013-2022 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}}
`
// ClefAppHelpTemplate is the template for the default, global app help topic.
ClefAppHelpTemplate = `NAME:
{{.App.Name}} - {{.App.Usage}}
Copyright 2013-2022 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}}
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}}
`
)
// HelpData is a one shot struct to pass to the usage template
type HelpData struct {
App interface{}
FlagGroups []FlagGroup
}
// FlagGroup is a collection of flags belonging to a single topic.
type FlagGroup struct {
Name string
Flags []cli.Flag
}
// 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(a), len(a) // ensure non categorized flags come last
for i, group := range a {
if iCat == group.Name {
iIdx = i
}
if jCat == group.Name {
jIdx = i
}
}
return iIdx < jIdx
}
func FlagCategory(flag cli.Flag, flagGroups []FlagGroup) string {
for _, category := range flagGroups {
for _, flg := range category.Flags {
if flg.GetName() == flag.GetName() {
return category.Name
}
}
}
return "MISC"
}
// NewApp creates an app with sane defaults. // NewApp creates an app with sane defaults.
func NewApp(gitCommit, gitDate, usage string) *cli.App { func NewApp(gitCommit, gitDate, usage string) *cli.App {
app := cli.NewApp() app := cli.NewApp()
app.EnableBashCompletion = true app.EnableBashCompletion = true
app.Name = filepath.Base(os.Args[0])
app.Author = ""
app.Email = ""
app.Version = params.VersionWithCommit(gitCommit, gitDate) app.Version = params.VersionWithCommit(gitCommit, gitDate)
app.Usage = usage app.Usage = usage
app.Copyright = "Copyright 2013-2022 The go-ethereum Authors"
app.Before = func(ctx *cli.Context) error {
MigrateGlobalFlags(ctx)
return nil
}
return app return app
} }
var migrationApplied = map[*cli.Command]struct{}{}
// MigrateGlobalFlags makes all global flag values available in the
// context. This should be called as early as possible in app.Before.
//
// Example:
//
// geth account new --keystore /tmp/mykeystore --lightkdf
//
// is equivalent after calling this method with:
//
// geth --keystore /tmp/mykeystore --lightkdf account new
//
// i.e. in the subcommand Action function of 'account new', ctx.Bool("lightkdf)
// will return true even if --lightkdf is set as a global option.
//
// This function may become unnecessary when https://github.com/urfave/cli/pull/1245 is merged.
func MigrateGlobalFlags(ctx *cli.Context) {
var iterate func(cs []*cli.Command, fn func(*cli.Command))
iterate = func(cs []*cli.Command, fn func(*cli.Command)) {
for _, cmd := range cs {
if _, ok := migrationApplied[cmd]; ok {
continue
}
migrationApplied[cmd] = struct{}{}
fn(cmd)
iterate(cmd.Subcommands, fn)
}
}
// This iterates over all commands and wraps their action function.
iterate(ctx.App.Commands, func(cmd *cli.Command) {
action := cmd.Action
cmd.Action = func(ctx *cli.Context) error {
doMigrateFlags(ctx)
return action(ctx)
}
})
}
func doMigrateFlags(ctx *cli.Context) {
for _, name := range ctx.FlagNames() {
for _, parent := range ctx.Lineage()[1:] {
if parent.IsSet(name) {
ctx.Set(name, parent.String(name))
break
}
}
}
}
func init() {
cli.FlagStringer = FlagString
}
// FlagString prints a single flag in help.
func FlagString(f cli.Flag) string {
df, ok := f.(cli.DocGenerationFlag)
if !ok {
return ""
}
needsPlaceholder := df.TakesValue()
placeholder := ""
if needsPlaceholder {
placeholder = "value"
}
namesText := pad(cli.FlagNamePrefixer(df.Names(), placeholder), 30)
defaultValueString := ""
if s := df.GetDefaultText(); s != "" {
defaultValueString = " (default: " + s + ")"
}
usage := strings.TrimSpace(df.GetUsage())
envHint := strings.TrimSpace(cli.FlagEnvHinter(df.GetEnvVars(), ""))
if len(envHint) > 0 {
usage += " " + envHint
}
usage = wordWrap(usage, 80)
usage = indent(usage, 10)
return fmt.Sprintf("\n %s%s\n%s", namesText, defaultValueString, usage)
}
func pad(s string, length int) string {
if len(s) < length {
s += strings.Repeat(" ", length-len(s))
}
return s
}
func indent(s string, nspace int) string {
ind := strings.Repeat(" ", nspace)
return ind + strings.ReplaceAll(s, "\n", "\n"+ind)
}
func wordWrap(s string, width int) string {
var (
output strings.Builder
lineLength = 0
)
for {
sp := strings.IndexByte(s, ' ')
var word string
if sp == -1 {
word = s
} else {
word = s[:sp]
}
wlen := len(word)
over := lineLength+wlen >= width
if over {
output.WriteByte('\n')
lineLength = 0
} else {
if lineLength != 0 {
output.WriteByte(' ')
lineLength++
}
}
output.WriteString(word)
lineLength += wlen
if sp == -1 {
break
}
s = s[wlen+1:]
}
return output.String()
}