mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +00:00
updated XDC WITH NEW MODE
This commit is contained in:
parent
e81137d533
commit
5d7c5ef101
5 changed files with 1163 additions and 0 deletions
109
cmd/XDC/bugcmd.go
Normal file
109
cmd/XDC/bugcmd.go
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/url"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/internal/browser"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
cli "gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bugCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(reportBug),
|
||||||
|
Name: "bug",
|
||||||
|
Usage: "opens a window to report a bug on the geth repo",
|
||||||
|
ArgsUsage: " ",
|
||||||
|
Category: "MISCELLANEOUS COMMANDS",
|
||||||
|
}
|
||||||
|
|
||||||
|
const issueUrl = "https://github.com/ethereum/go-ethereum/issues/new"
|
||||||
|
|
||||||
|
// reportBug reports a bug by opening a new URL to the go-ethereum GH issue
|
||||||
|
// tracker and setting default values as the issue body.
|
||||||
|
func reportBug(ctx *cli.Context) error {
|
||||||
|
// execute template and write contents to buff
|
||||||
|
var buff bytes.Buffer
|
||||||
|
|
||||||
|
fmt.Fprintln(&buff, header)
|
||||||
|
fmt.Fprintln(&buff, "Version:", params.Version)
|
||||||
|
fmt.Fprintln(&buff, "Go Version:", runtime.Version())
|
||||||
|
fmt.Fprintln(&buff, "OS:", runtime.GOOS)
|
||||||
|
printOSDetails(&buff)
|
||||||
|
|
||||||
|
// open a new GH issue
|
||||||
|
if !browser.Open(issueUrl + "?body=" + url.QueryEscape(buff.String())) {
|
||||||
|
fmt.Printf("Please file a new issue at %s using this template:\n%s", issueUrl, buff.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// copied from the Go source. Copyright 2017 The Go Authors
|
||||||
|
func printOSDetails(w io.Writer) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
printCmdOut(w, "uname -v: ", "uname", "-v")
|
||||||
|
printCmdOut(w, "", "sw_vers")
|
||||||
|
case "linux":
|
||||||
|
printCmdOut(w, "uname -sr: ", "uname", "-sr")
|
||||||
|
printCmdOut(w, "", "lsb_release", "-a")
|
||||||
|
case "openbsd", "netbsd", "freebsd", "dragonfly":
|
||||||
|
printCmdOut(w, "uname -v: ", "uname", "-v")
|
||||||
|
case "solaris":
|
||||||
|
out, err := ioutil.ReadFile("/etc/release")
|
||||||
|
if err == nil {
|
||||||
|
fmt.Fprintf(w, "/etc/release: %s\n", out)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("failed to read /etc/release: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printCmdOut prints the output of running the given command.
|
||||||
|
// It ignores failures; 'go bug' is best effort.
|
||||||
|
//
|
||||||
|
// copied from the Go source. Copyright 2017 The Go Authors
|
||||||
|
func printCmdOut(w io.Writer, prefix, path string, args ...string) {
|
||||||
|
cmd := exec.Command(path, args...)
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
const header = `Please answer these questions before submitting your issue. Thanks!
|
||||||
|
|
||||||
|
#### What did you do?
|
||||||
|
|
||||||
|
#### What did you expect to see?
|
||||||
|
|
||||||
|
#### What did you see instead?
|
||||||
|
|
||||||
|
#### System details
|
||||||
|
`
|
||||||
473
cmd/XDC/chaincmd.go
Normal file
473
cmd/XDC/chaincmd.go
Normal file
|
|
@ -0,0 +1,473 @@
|
||||||
|
// Copyright 2015 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/console"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
initCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(initGenesis),
|
||||||
|
Name: "init",
|
||||||
|
Usage: "Bootstrap and initialize a new genesis block",
|
||||||
|
ArgsUsage: "<genesisPath>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
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
|
||||||
|
participating.
|
||||||
|
|
||||||
|
It expects the genesis file as argument.`,
|
||||||
|
}
|
||||||
|
importCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(importChain),
|
||||||
|
Name: "import",
|
||||||
|
Usage: "Import a blockchain file",
|
||||||
|
ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
utils.GCModeFlag,
|
||||||
|
utils.CacheDatabaseFlag,
|
||||||
|
utils.CacheGCFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.`,
|
||||||
|
}
|
||||||
|
exportCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(exportChain),
|
||||||
|
Name: "export",
|
||||||
|
Usage: "Export blockchain into file",
|
||||||
|
ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
Requires a first argument of the file to write to.
|
||||||
|
Optional second and third arguments control the first and
|
||||||
|
last block to write. In this mode, the file will be appended
|
||||||
|
if already existing.`,
|
||||||
|
}
|
||||||
|
importPreimagesCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(importPreimages),
|
||||||
|
Name: "import-preimages",
|
||||||
|
Usage: "Import the preimage database from an RLP stream",
|
||||||
|
ArgsUsage: "<datafile>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The import-preimages command imports hash preimages from an RLP encoded stream.`,
|
||||||
|
}
|
||||||
|
exportPreimagesCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(exportPreimages),
|
||||||
|
Name: "export-preimages",
|
||||||
|
Usage: "Export the preimage database into an RLP stream",
|
||||||
|
ArgsUsage: "<dumpfile>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The export-preimages command export hash preimages to an RLP encoded stream`,
|
||||||
|
}
|
||||||
|
copydbCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(copyDb),
|
||||||
|
Name: "copydb",
|
||||||
|
Usage: "Create a local chain from a target chaindata folder",
|
||||||
|
ArgsUsage: "<sourceChaindataDir>",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.SyncModeFlag,
|
||||||
|
utils.FakePoWFlag,
|
||||||
|
utils.TestnetFlag,
|
||||||
|
utils.RinkebyFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The first argument must be the directory containing the blockchain to download from`,
|
||||||
|
}
|
||||||
|
removedbCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(removeDB),
|
||||||
|
Name: "removedb",
|
||||||
|
Usage: "Remove blockchain and state databases",
|
||||||
|
ArgsUsage: " ",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
Remove blockchain and state databases`,
|
||||||
|
}
|
||||||
|
dumpCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(dump),
|
||||||
|
Name: "dump",
|
||||||
|
Usage: "Dump a specific block from storage",
|
||||||
|
ArgsUsage: "[<blockHash> | <blockNum>]...",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
utils.DataDirFlag,
|
||||||
|
utils.CacheFlag,
|
||||||
|
utils.LightModeFlag,
|
||||||
|
},
|
||||||
|
Category: "BLOCKCHAIN COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The arguments are interpreted as block numbers or hashes.
|
||||||
|
Use "ethereum dump 0" to dump the genesis block.`,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// initGenesis will initialise the given JSON format genesis file and writes it as
|
||||||
|
// the zero'd block (i.e. genesis) or will fail hard if it can't succeed.
|
||||||
|
func initGenesis(ctx *cli.Context) error {
|
||||||
|
// Make sure we have a valid genesis JSON
|
||||||
|
genesisPath := ctx.Args().First()
|
||||||
|
if len(genesisPath) == 0 {
|
||||||
|
utils.Fatalf("Must supply path to genesis JSON file")
|
||||||
|
}
|
||||||
|
file, err := os.Open(genesisPath)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read genesis file: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
genesis := new(core.Genesis)
|
||||||
|
if err := json.NewDecoder(file).Decode(genesis); err != nil {
|
||||||
|
utils.Fatalf("invalid genesis file: %v", err)
|
||||||
|
}
|
||||||
|
// Open an initialise both full and light databases
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
for _, name := range []string{"chaindata", "lightchaindata"} {
|
||||||
|
chaindb, err := stack.OpenDatabase(name, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to open database: %v", err)
|
||||||
|
}
|
||||||
|
_, hash, err := core.SetupGenesisBlock(chaindb, genesis)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to write genesis block: %v", err)
|
||||||
|
}
|
||||||
|
log.Info("Successfully wrote genesis state", "database", name, "hash", hash)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func importChain(ctx *cli.Context) error {
|
||||||
|
if len(ctx.Args()) < 1 {
|
||||||
|
utils.Fatalf("This command requires an argument.")
|
||||||
|
}
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
chain, chainDb := utils.MakeChain(ctx, stack)
|
||||||
|
defer chainDb.Close()
|
||||||
|
|
||||||
|
// Start periodically gathering memory profiles
|
||||||
|
var peakMemAlloc, peakMemSys uint64
|
||||||
|
go func() {
|
||||||
|
stats := new(runtime.MemStats)
|
||||||
|
for {
|
||||||
|
runtime.ReadMemStats(stats)
|
||||||
|
if atomic.LoadUint64(&peakMemAlloc) < stats.Alloc {
|
||||||
|
atomic.StoreUint64(&peakMemAlloc, stats.Alloc)
|
||||||
|
}
|
||||||
|
if atomic.LoadUint64(&peakMemSys) < stats.Sys {
|
||||||
|
atomic.StoreUint64(&peakMemSys, stats.Sys)
|
||||||
|
}
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// Import the chain
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
if len(ctx.Args()) == 1 {
|
||||||
|
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
|
||||||
|
log.Error("Import error", "err", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, arg := range ctx.Args() {
|
||||||
|
if err := utils.ImportChain(chain, arg); err != nil {
|
||||||
|
log.Error("Import error", "file", arg, "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chain.Stop()
|
||||||
|
fmt.Printf("Import done in %v.\n\n", time.Since(start))
|
||||||
|
|
||||||
|
// Output pre-compaction stats mostly to see the import trashing
|
||||||
|
db := chainDb.(*ethdb.LDBDatabase)
|
||||||
|
|
||||||
|
stats, err := db.LDB().GetProperty("leveldb.stats")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read database stats: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(stats)
|
||||||
|
|
||||||
|
ioStats, err := db.LDB().GetProperty("leveldb.iostats")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(ioStats)
|
||||||
|
|
||||||
|
fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses())
|
||||||
|
fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads())
|
||||||
|
|
||||||
|
// Print the memory statistics used by the importing
|
||||||
|
mem := new(runtime.MemStats)
|
||||||
|
runtime.ReadMemStats(mem)
|
||||||
|
|
||||||
|
fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(atomic.LoadUint64(&peakMemAlloc))/1024/1024)
|
||||||
|
fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(atomic.LoadUint64(&peakMemSys))/1024/1024)
|
||||||
|
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
|
||||||
|
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
|
||||||
|
|
||||||
|
if ctx.GlobalIsSet(utils.NoCompactionFlag.Name) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compact the entire database to more accurately measure disk io and print the stats
|
||||||
|
start = time.Now()
|
||||||
|
fmt.Println("Compacting entire database...")
|
||||||
|
if err = db.LDB().CompactRange(util.Range{}); err != nil {
|
||||||
|
utils.Fatalf("Compaction failed: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
|
||||||
|
|
||||||
|
stats, err = db.LDB().GetProperty("leveldb.stats")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read database stats: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(stats)
|
||||||
|
|
||||||
|
ioStats, err = db.LDB().GetProperty("leveldb.iostats")
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(ioStats)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportChain(ctx *cli.Context) error {
|
||||||
|
if len(ctx.Args()) < 1 {
|
||||||
|
utils.Fatalf("This command requires an argument.")
|
||||||
|
}
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
chain, _ := utils.MakeChain(ctx, stack)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
fp := ctx.Args().First()
|
||||||
|
if len(ctx.Args()) < 3 {
|
||||||
|
err = utils.ExportChain(chain, fp)
|
||||||
|
} else {
|
||||||
|
// This can be improved to allow for numbers larger than 9223372036854775807
|
||||||
|
first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64)
|
||||||
|
last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
|
||||||
|
if ferr != nil || lerr != nil {
|
||||||
|
utils.Fatalf("Export error in parsing parameters: block number not an integer\n")
|
||||||
|
}
|
||||||
|
if first < 0 || last < 0 {
|
||||||
|
utils.Fatalf("Export error: block number must be greater than 0\n")
|
||||||
|
}
|
||||||
|
err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// importPreimages imports preimage data from the specified file.
|
||||||
|
func importPreimages(ctx *cli.Context) error {
|
||||||
|
if len(ctx.Args()) < 1 {
|
||||||
|
utils.Fatalf("This command requires an argument.")
|
||||||
|
}
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil {
|
||||||
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// exportPreimages dumps the preimage data to specified json file in streaming way.
|
||||||
|
func exportPreimages(ctx *cli.Context) error {
|
||||||
|
if len(ctx.Args()) < 1 {
|
||||||
|
utils.Fatalf("This command requires an argument.")
|
||||||
|
}
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil {
|
||||||
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Export done in %v\n", time.Since(start))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyDb(ctx *cli.Context) error {
|
||||||
|
// Ensure we have a source chain directory to copy
|
||||||
|
if len(ctx.Args()) != 1 {
|
||||||
|
utils.Fatalf("Source chaindata directory path argument missing")
|
||||||
|
}
|
||||||
|
// Initialize a new chain for the running node to sync into
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
chain, chainDb := utils.MakeChain(ctx, stack)
|
||||||
|
|
||||||
|
syncmode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode)
|
||||||
|
dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil)
|
||||||
|
|
||||||
|
// Create a source peer to satisfy downloader requests from
|
||||||
|
db, err := ethdb.NewLDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hc, err := core.NewHeaderChain(db, chain.Config(), chain.Engine(), func() bool { return false })
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
peer := downloader.NewFakePeer("local", db, hc, dl)
|
||||||
|
if err = dl.RegisterPeer("local", 63, peer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Synchronise with the simulated peer
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
currentHeader := hc.CurrentHeader()
|
||||||
|
if err = dl.Synchronise("local", currentHeader.Hash(), hc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()), syncmode); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for dl.Synchronising() {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
fmt.Printf("Database copy done in %v\n", time.Since(start))
|
||||||
|
|
||||||
|
// Compact the entire database to remove any sync overhead
|
||||||
|
start = time.Now()
|
||||||
|
fmt.Println("Compacting entire database...")
|
||||||
|
if err = chainDb.(*ethdb.LDBDatabase).LDB().CompactRange(util.Range{}); err != nil {
|
||||||
|
utils.Fatalf("Compaction failed: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeDB(ctx *cli.Context) error {
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
|
||||||
|
for _, name := range []string{"chaindata", "lightchaindata"} {
|
||||||
|
// Ensure the database exists in the first place
|
||||||
|
logger := log.New("database", name)
|
||||||
|
|
||||||
|
dbdir := stack.ResolvePath(name)
|
||||||
|
if !common.FileExist(dbdir) {
|
||||||
|
logger.Info("Database doesn't exist, skipping", "path", dbdir)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Confirm removal and execute
|
||||||
|
fmt.Println(dbdir)
|
||||||
|
confirm, err := console.Stdin.PromptConfirm("Remove this database?")
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
case !confirm:
|
||||||
|
logger.Warn("Database deletion aborted")
|
||||||
|
default:
|
||||||
|
start := time.Now()
|
||||||
|
os.RemoveAll(dbdir)
|
||||||
|
logger.Info("Database successfully deleted", "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dump(ctx *cli.Context) error {
|
||||||
|
stack := makeFullNode(ctx)
|
||||||
|
chain, chainDb := utils.MakeChain(ctx, stack)
|
||||||
|
for _, arg := range ctx.Args() {
|
||||||
|
var block *types.Block
|
||||||
|
if hashish(arg) {
|
||||||
|
block = chain.GetBlockByHash(common.HexToHash(arg))
|
||||||
|
} else {
|
||||||
|
num, _ := strconv.Atoi(arg)
|
||||||
|
block = chain.GetBlockByNumber(uint64(num))
|
||||||
|
}
|
||||||
|
if block == nil {
|
||||||
|
fmt.Println("{}")
|
||||||
|
utils.Fatalf("block not found")
|
||||||
|
} else {
|
||||||
|
state, err := state.New(block.Root(), state.NewDatabase(chainDb))
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("could not create new state: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", state.Dump())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chainDb.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hashish returns true for strings that look like hashes.
|
||||||
|
func hashish(x string) bool {
|
||||||
|
_, err := strconv.Atoi(x)
|
||||||
|
return err != nil
|
||||||
|
}
|
||||||
198
cmd/XDC/config.go
Normal file
198
cmd/XDC/config.go
Normal file
|
|
@ -0,0 +1,198 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
cli "gopkg.in/urfave/cli.v1"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/dashboard"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||||
|
"github.com/naoina/toml"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dumpConfigCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(dumpConfig),
|
||||||
|
Name: "dumpconfig",
|
||||||
|
Usage: "Show configuration values",
|
||||||
|
ArgsUsage: "",
|
||||||
|
Flags: append(append(nodeFlags, rpcFlags...), whisperFlags...),
|
||||||
|
Category: "MISCELLANEOUS COMMANDS",
|
||||||
|
Description: `The dumpconfig command shows configuration values.`,
|
||||||
|
}
|
||||||
|
|
||||||
|
configFileFlag = cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Usage: "TOML configuration file",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// These settings ensure that TOML keys use the same names as Go struct fields.
|
||||||
|
var tomlSettings = toml.Config{
|
||||||
|
NormFieldName: func(rt reflect.Type, key string) string {
|
||||||
|
return key
|
||||||
|
},
|
||||||
|
FieldToKey: func(rt reflect.Type, field string) string {
|
||||||
|
return field
|
||||||
|
},
|
||||||
|
MissingField: func(rt reflect.Type, field string) error {
|
||||||
|
link := ""
|
||||||
|
if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" {
|
||||||
|
link = fmt.Sprintf(", see https://godoc.org/%s#%s for available fields", rt.PkgPath(), rt.Name())
|
||||||
|
}
|
||||||
|
return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type ethstatsConfig struct {
|
||||||
|
URL string `toml:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type gethConfig struct {
|
||||||
|
Eth eth.Config
|
||||||
|
Shh whisper.Config
|
||||||
|
Node node.Config
|
||||||
|
Ethstats ethstatsConfig
|
||||||
|
Dashboard dashboard.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfig(file string, cfg *gethConfig) error {
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
err = tomlSettings.NewDecoder(bufio.NewReader(f)).Decode(cfg)
|
||||||
|
// Add file name to errors that have a line number.
|
||||||
|
if _, ok := err.(*toml.LineError); ok {
|
||||||
|
err = errors.New(file + ", " + err.Error())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultNodeConfig() node.Config {
|
||||||
|
cfg := node.DefaultConfig
|
||||||
|
cfg.Name = clientIdentifier
|
||||||
|
cfg.Version = params.VersionWithCommit(gitCommit)
|
||||||
|
cfg.HTTPModules = append(cfg.HTTPModules, "eth", "shh")
|
||||||
|
cfg.WSModules = append(cfg.WSModules, "eth", "shh")
|
||||||
|
cfg.IPCPath = "geth.ipc"
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
|
||||||
|
// Load defaults.
|
||||||
|
cfg := gethConfig{
|
||||||
|
Eth: eth.DefaultConfig,
|
||||||
|
Shh: whisper.DefaultConfig,
|
||||||
|
Node: defaultNodeConfig(),
|
||||||
|
Dashboard: dashboard.DefaultConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load config file.
|
||||||
|
if file := ctx.GlobalString(configFileFlag.Name); file != "" {
|
||||||
|
if err := loadConfig(file, &cfg); err != nil {
|
||||||
|
utils.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply flags.
|
||||||
|
utils.SetNodeConfig(ctx, &cfg.Node)
|
||||||
|
stack, err := node.New(&cfg.Node)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to create the protocol stack: %v", err)
|
||||||
|
}
|
||||||
|
utils.SetEthConfig(ctx, stack, &cfg.Eth)
|
||||||
|
if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) {
|
||||||
|
cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.SetShhConfig(ctx, stack, &cfg.Shh)
|
||||||
|
utils.SetDashboardConfig(ctx, &cfg.Dashboard)
|
||||||
|
|
||||||
|
return stack, cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// enableWhisper returns true in case one of the whisper flags is set.
|
||||||
|
func enableWhisper(ctx *cli.Context) bool {
|
||||||
|
for _, flag := range whisperFlags {
|
||||||
|
if ctx.GlobalIsSet(flag.GetName()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
|
stack, cfg := makeConfigNode(ctx)
|
||||||
|
|
||||||
|
utils.RegisterEthService(stack, &cfg.Eth)
|
||||||
|
|
||||||
|
if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
|
||||||
|
utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit)
|
||||||
|
}
|
||||||
|
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
|
||||||
|
shhEnabled := enableWhisper(ctx)
|
||||||
|
shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name)
|
||||||
|
if shhEnabled || shhAutoEnabled {
|
||||||
|
if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) {
|
||||||
|
cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name))
|
||||||
|
}
|
||||||
|
if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) {
|
||||||
|
cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name)
|
||||||
|
}
|
||||||
|
utils.RegisterShhService(stack, &cfg.Shh)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Ethereum Stats daemon if requested.
|
||||||
|
if cfg.Ethstats.URL != "" {
|
||||||
|
utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
|
||||||
|
}
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// dumpConfig is the dumpconfig command.
|
||||||
|
func dumpConfig(ctx *cli.Context) error {
|
||||||
|
_, cfg := makeConfigNode(ctx)
|
||||||
|
comment := ""
|
||||||
|
|
||||||
|
if cfg.Eth.Genesis != nil {
|
||||||
|
cfg.Eth.Genesis = nil
|
||||||
|
comment += "# Note: this config doesn't contain the genesis block.\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := tomlSettings.Marshal(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
io.WriteString(os.Stdout, comment)
|
||||||
|
os.Stdout.Write(out)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
220
cmd/XDC/consolecmd.go
Normal file
220
cmd/XDC/consolecmd.go
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/console"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag}
|
||||||
|
|
||||||
|
consoleCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(localConsole),
|
||||||
|
Name: "console",
|
||||||
|
Usage: "Start an interactive JavaScript environment",
|
||||||
|
Flags: append(append(append(nodeFlags, rpcFlags...), consoleFlags...), whisperFlags...),
|
||||||
|
Category: "CONSOLE COMMANDS",
|
||||||
|
Description: `
|
||||||
|
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.
|
||||||
|
See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.`,
|
||||||
|
}
|
||||||
|
|
||||||
|
attachCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(remoteConsole),
|
||||||
|
Name: "attach",
|
||||||
|
Usage: "Start an interactive JavaScript environment (connect to node)",
|
||||||
|
ArgsUsage: "[endpoint]",
|
||||||
|
Flags: append(consoleFlags, utils.DataDirFlag),
|
||||||
|
Category: "CONSOLE COMMANDS",
|
||||||
|
Description: `
|
||||||
|
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.
|
||||||
|
See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console.
|
||||||
|
This command allows to open a console on a running geth node.`,
|
||||||
|
}
|
||||||
|
|
||||||
|
javascriptCommand = cli.Command{
|
||||||
|
Action: utils.MigrateFlags(ephemeralConsole),
|
||||||
|
Name: "js",
|
||||||
|
Usage: "Execute the specified JavaScript files",
|
||||||
|
ArgsUsage: "<jsfile> [jsfile...]",
|
||||||
|
Flags: append(nodeFlags, consoleFlags...),
|
||||||
|
Category: "CONSOLE COMMANDS",
|
||||||
|
Description: `
|
||||||
|
The JavaScript VM exposes a node admin interface as well as the Ðapp
|
||||||
|
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Console`,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// localConsole starts a new geth node, attaching a JavaScript console to it at the
|
||||||
|
// same time.
|
||||||
|
func localConsole(ctx *cli.Context) error {
|
||||||
|
// Create and start the node based on the CLI flags
|
||||||
|
node := makeFullNode(ctx)
|
||||||
|
startNode(ctx, node)
|
||||||
|
defer node.Stop()
|
||||||
|
|
||||||
|
// Attach to the newly started node and start the JavaScript console
|
||||||
|
client, err := node.Attach()
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
|
||||||
|
}
|
||||||
|
config := console.Config{
|
||||||
|
DataDir: utils.MakeDataDir(ctx),
|
||||||
|
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name),
|
||||||
|
Client: client,
|
||||||
|
Preload: utils.MakeConsolePreloads(ctx),
|
||||||
|
}
|
||||||
|
|
||||||
|
console, err := console.New(config)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to start the JavaScript console: %v", err)
|
||||||
|
}
|
||||||
|
defer console.Stop(false)
|
||||||
|
|
||||||
|
// If only a short execution was requested, evaluate and return
|
||||||
|
if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" {
|
||||||
|
console.Evaluate(script)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Otherwise print the welcome screen and enter interactive mode
|
||||||
|
console.Welcome()
|
||||||
|
console.Interactive()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// remoteConsole will connect to a remote geth instance, attaching a JavaScript
|
||||||
|
// console to it.
|
||||||
|
func remoteConsole(ctx *cli.Context) error {
|
||||||
|
// Attach to a remotely running geth instance and start the JavaScript console
|
||||||
|
endpoint := ctx.Args().First()
|
||||||
|
if endpoint == "" {
|
||||||
|
path := node.DefaultDataDir()
|
||||||
|
if ctx.GlobalIsSet(utils.DataDirFlag.Name) {
|
||||||
|
path = ctx.GlobalString(utils.DataDirFlag.Name)
|
||||||
|
}
|
||||||
|
if path != "" {
|
||||||
|
if ctx.GlobalBool(utils.TestnetFlag.Name) {
|
||||||
|
path = filepath.Join(path, "testnet")
|
||||||
|
} else if ctx.GlobalBool(utils.RinkebyFlag.Name) {
|
||||||
|
path = filepath.Join(path, "rinkeby")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endpoint = fmt.Sprintf("%s/geth.ipc", path)
|
||||||
|
}
|
||||||
|
client, err := dialRPC(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Unable to attach to remote geth: %v", err)
|
||||||
|
}
|
||||||
|
config := console.Config{
|
||||||
|
DataDir: utils.MakeDataDir(ctx),
|
||||||
|
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name),
|
||||||
|
Client: client,
|
||||||
|
Preload: utils.MakeConsolePreloads(ctx),
|
||||||
|
}
|
||||||
|
|
||||||
|
console, err := console.New(config)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to start the JavaScript console: %v", err)
|
||||||
|
}
|
||||||
|
defer console.Stop(false)
|
||||||
|
|
||||||
|
if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" {
|
||||||
|
console.Evaluate(script)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise print the welcome screen and enter interactive mode
|
||||||
|
console.Welcome()
|
||||||
|
console.Interactive()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialRPC returns a RPC client which connects to the given endpoint.
|
||||||
|
// The check for empty endpoint implements the defaulting logic
|
||||||
|
// for "geth attach" and "geth monitor" with no argument.
|
||||||
|
func dialRPC(endpoint string) (*rpc.Client, error) {
|
||||||
|
if endpoint == "" {
|
||||||
|
endpoint = node.DefaultIPCEndpoint(clientIdentifier)
|
||||||
|
} else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") {
|
||||||
|
// Backwards compatibility with geth < 1.5 which required
|
||||||
|
// these prefixes.
|
||||||
|
endpoint = endpoint[4:]
|
||||||
|
}
|
||||||
|
return rpc.Dial(endpoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript
|
||||||
|
// console to it, executes each of the files specified as arguments and tears
|
||||||
|
// everything down.
|
||||||
|
func ephemeralConsole(ctx *cli.Context) error {
|
||||||
|
// Create and start the node based on the CLI flags
|
||||||
|
node := makeFullNode(ctx)
|
||||||
|
startNode(ctx, node)
|
||||||
|
defer node.Stop()
|
||||||
|
|
||||||
|
// Attach to the newly started node and start the JavaScript console
|
||||||
|
client, err := node.Attach()
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
|
||||||
|
}
|
||||||
|
config := console.Config{
|
||||||
|
DataDir: utils.MakeDataDir(ctx),
|
||||||
|
DocRoot: ctx.GlobalString(utils.JSpathFlag.Name),
|
||||||
|
Client: client,
|
||||||
|
Preload: utils.MakeConsolePreloads(ctx),
|
||||||
|
}
|
||||||
|
|
||||||
|
console, err := console.New(config)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Failed to start the JavaScript console: %v", err)
|
||||||
|
}
|
||||||
|
defer console.Stop(false)
|
||||||
|
|
||||||
|
// Evaluate each of the specified JavaScript files
|
||||||
|
for _, file := range ctx.Args() {
|
||||||
|
if err = console.Execute(file); err != nil {
|
||||||
|
utils.Fatalf("Failed to execute %s: %v", file, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait for pending callbacks, but stop for Ctrl-C.
|
||||||
|
abort := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-abort
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
console.Stop(true)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
163
cmd/XDC/consolecmd_test.go
Normal file
163
cmd/XDC/consolecmd_test.go
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0"
|
||||||
|
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tests that a node embedded within a console can be started up properly and
|
||||||
|
// then terminated by closing the input stream.
|
||||||
|
func TestConsoleWelcome(t *testing.T) {
|
||||||
|
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
|
||||||
|
|
||||||
|
// Start a geth console, make sure it's cleaned up and terminate the console
|
||||||
|
geth := runGeth(t,
|
||||||
|
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||||
|
"--etherbase", coinbase, "--shh",
|
||||||
|
"console")
|
||||||
|
|
||||||
|
// Gather all the infos the welcome message needs to contain
|
||||||
|
geth.SetTemplateFunc("goos", func() string { return runtime.GOOS })
|
||||||
|
geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
|
||||||
|
geth.SetTemplateFunc("gover", runtime.Version)
|
||||||
|
geth.SetTemplateFunc("gethver", func() string { return params.Version })
|
||||||
|
geth.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
|
||||||
|
geth.SetTemplateFunc("apis", func() string { return ipcAPIs })
|
||||||
|
|
||||||
|
// Verify the actual welcome message to the required template
|
||||||
|
geth.Expect(`
|
||||||
|
Welcome to the Geth JavaScript console!
|
||||||
|
|
||||||
|
instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}}
|
||||||
|
coinbase: {{.Etherbase}}
|
||||||
|
at block: 0 ({{niltime}})
|
||||||
|
datadir: {{.Datadir}}
|
||||||
|
modules: {{apis}}
|
||||||
|
|
||||||
|
> {{.InputLine "exit"}}
|
||||||
|
`)
|
||||||
|
geth.ExpectExit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that a console can be attached to a running node via various means.
|
||||||
|
func TestIPCAttachWelcome(t *testing.T) {
|
||||||
|
// Configure the instance for IPC attachement
|
||||||
|
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
|
||||||
|
var ipc string
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
ipc = `\\.\pipe\geth` + strconv.Itoa(trulyRandInt(100000, 999999))
|
||||||
|
} else {
|
||||||
|
ws := tmpdir(t)
|
||||||
|
defer os.RemoveAll(ws)
|
||||||
|
ipc = filepath.Join(ws, "geth.ipc")
|
||||||
|
}
|
||||||
|
// Note: we need --shh because testAttachWelcome checks for default
|
||||||
|
// list of ipc modules and shh is included there.
|
||||||
|
geth := runGeth(t,
|
||||||
|
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||||
|
"--etherbase", coinbase, "--shh", "--ipcpath", ipc)
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
||||||
|
testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs)
|
||||||
|
|
||||||
|
geth.Interrupt()
|
||||||
|
geth.ExpectExit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHTTPAttachWelcome(t *testing.T) {
|
||||||
|
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
|
||||||
|
port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P
|
||||||
|
geth := runGeth(t,
|
||||||
|
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||||
|
"--etherbase", coinbase, "--rpc", "--rpcport", port)
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
||||||
|
testAttachWelcome(t, geth, "http://localhost:"+port, httpAPIs)
|
||||||
|
|
||||||
|
geth.Interrupt()
|
||||||
|
geth.ExpectExit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWSAttachWelcome(t *testing.T) {
|
||||||
|
coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
|
||||||
|
port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P
|
||||||
|
|
||||||
|
geth := runGeth(t,
|
||||||
|
"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none",
|
||||||
|
"--etherbase", coinbase, "--ws", "--wsport", port)
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open
|
||||||
|
testAttachWelcome(t, geth, "ws://localhost:"+port, httpAPIs)
|
||||||
|
|
||||||
|
geth.Interrupt()
|
||||||
|
geth.ExpectExit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
|
||||||
|
// Attach to a running geth note and terminate immediately
|
||||||
|
attach := runGeth(t, "attach", endpoint)
|
||||||
|
defer attach.ExpectExit()
|
||||||
|
attach.CloseStdin()
|
||||||
|
|
||||||
|
// Gather all the infos the welcome message needs to contain
|
||||||
|
attach.SetTemplateFunc("goos", func() string { return runtime.GOOS })
|
||||||
|
attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
|
||||||
|
attach.SetTemplateFunc("gover", runtime.Version)
|
||||||
|
attach.SetTemplateFunc("gethver", func() string { return params.Version })
|
||||||
|
attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase })
|
||||||
|
attach.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) })
|
||||||
|
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
|
||||||
|
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
||||||
|
attach.SetTemplateFunc("apis", func() string { return apis })
|
||||||
|
|
||||||
|
// Verify the actual welcome message to the required template
|
||||||
|
attach.Expect(`
|
||||||
|
Welcome to the Geth JavaScript console!
|
||||||
|
|
||||||
|
instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}}
|
||||||
|
coinbase: {{etherbase}}
|
||||||
|
at block: 0 ({{niltime}}){{if ipc}}
|
||||||
|
datadir: {{datadir}}{{end}}
|
||||||
|
modules: {{apis}}
|
||||||
|
|
||||||
|
> {{.InputLine "exit" }}
|
||||||
|
`)
|
||||||
|
attach.ExpectExit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// trulyRandInt generates a crypto random integer used by the console tests to
|
||||||
|
// not clash network ports with other tests running cocurrently.
|
||||||
|
func trulyRandInt(lo, hi int) int {
|
||||||
|
num, _ := rand.Int(rand.Reader, big.NewInt(int64(hi-lo)))
|
||||||
|
return int(num.Int64()) + lo
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue