|
|
|
@ -1,20 +1,20 @@ |
|
|
|
|
package utils |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"github.com/ethereum/eth-go" |
|
|
|
|
"github.com/ethereum/eth-go/ethminer" |
|
|
|
|
"github.com/ethereum/eth-go/ethpub" |
|
|
|
|
"github.com/ethereum/eth-go/ethrpc" |
|
|
|
|
"github.com/ethereum/eth-go/ethutil" |
|
|
|
|
"github.com/ethereum/eth-go/ethlog" |
|
|
|
|
"log" |
|
|
|
|
"io" |
|
|
|
|
"path" |
|
|
|
|
"os" |
|
|
|
|
"os/signal" |
|
|
|
|
"fmt" |
|
|
|
|
"time" |
|
|
|
|
"strings" |
|
|
|
|
"fmt" |
|
|
|
|
"github.com/ethereum/eth-go" |
|
|
|
|
"github.com/ethereum/eth-go/ethlog" |
|
|
|
|
"github.com/ethereum/eth-go/ethminer" |
|
|
|
|
"github.com/ethereum/eth-go/ethpub" |
|
|
|
|
"github.com/ethereum/eth-go/ethrpc" |
|
|
|
|
"github.com/ethereum/eth-go/ethutil" |
|
|
|
|
"io" |
|
|
|
|
"log" |
|
|
|
|
"os" |
|
|
|
|
"os/signal" |
|
|
|
|
"path" |
|
|
|
|
"strings" |
|
|
|
|
"time" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var logger = ethlog.NewLogger("CLI") |
|
|
|
@ -22,142 +22,142 @@ var interruptCallbacks = []func(os.Signal){} |
|
|
|
|
|
|
|
|
|
// Register interrupt handlers callbacks
|
|
|
|
|
func RegisterInterrupt(cb func(os.Signal)) { |
|
|
|
|
interruptCallbacks = append(interruptCallbacks, cb) |
|
|
|
|
interruptCallbacks = append(interruptCallbacks, cb) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// go routine that call interrupt handlers in order of registering
|
|
|
|
|
func HandleInterrupt() { |
|
|
|
|
c := make(chan os.Signal, 1) |
|
|
|
|
go func() { |
|
|
|
|
signal.Notify(c, os.Interrupt) |
|
|
|
|
for sig := range c { |
|
|
|
|
logger.Errorf("Shutting down (%v) ... \n", sig) |
|
|
|
|
RunInterruptCallbacks(sig) |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
c := make(chan os.Signal, 1) |
|
|
|
|
go func() { |
|
|
|
|
signal.Notify(c, os.Interrupt) |
|
|
|
|
for sig := range c { |
|
|
|
|
logger.Errorf("Shutting down (%v) ... \n", sig) |
|
|
|
|
RunInterruptCallbacks(sig) |
|
|
|
|
} |
|
|
|
|
}() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func RunInterruptCallbacks(sig os.Signal) { |
|
|
|
|
for _, cb := range interruptCallbacks { |
|
|
|
|
cb(sig) |
|
|
|
|
} |
|
|
|
|
for _, cb := range interruptCallbacks { |
|
|
|
|
cb(sig) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func AbsolutePath(Datadir string, filename string) string { |
|
|
|
|
if path.IsAbs(filename) { |
|
|
|
|
return filename |
|
|
|
|
} |
|
|
|
|
return path.Join(Datadir, filename) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func openLogFile (Datadir string, filename string) *os.File { |
|
|
|
|
path := AbsolutePath(Datadir, filename) |
|
|
|
|
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
|
|
|
|
if err != nil { |
|
|
|
|
panic(fmt.Sprintf("error opening log file '%s': %v", filename, err)) |
|
|
|
|
} |
|
|
|
|
return file |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func confirm (message string) bool { |
|
|
|
|
fmt.Println(message, "Are you sure? (y/n)") |
|
|
|
|
var r string |
|
|
|
|
fmt.Scanln(&r) |
|
|
|
|
for ; ; fmt.Scanln(&r) { |
|
|
|
|
if r == "n" || r == "y" { |
|
|
|
|
break |
|
|
|
|
} else { |
|
|
|
|
fmt.Printf("Yes or no?", r) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return r == "y" |
|
|
|
|
if path.IsAbs(filename) { |
|
|
|
|
return filename |
|
|
|
|
} |
|
|
|
|
return path.Join(Datadir, filename) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func openLogFile(Datadir string, filename string) *os.File { |
|
|
|
|
path := AbsolutePath(Datadir, filename) |
|
|
|
|
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) |
|
|
|
|
if err != nil { |
|
|
|
|
panic(fmt.Sprintf("error opening log file '%s': %v", filename, err)) |
|
|
|
|
} |
|
|
|
|
return file |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func confirm(message string) bool { |
|
|
|
|
fmt.Println(message, "Are you sure? (y/n)") |
|
|
|
|
var r string |
|
|
|
|
fmt.Scanln(&r) |
|
|
|
|
for ; ; fmt.Scanln(&r) { |
|
|
|
|
if r == "n" || r == "y" { |
|
|
|
|
break |
|
|
|
|
} else { |
|
|
|
|
fmt.Printf("Yes or no?", r) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return r == "y" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func InitDataDir(Datadir string) { |
|
|
|
|
_, err := os.Stat(Datadir) |
|
|
|
|
if err != nil { |
|
|
|
|
if os.IsNotExist(err) { |
|
|
|
|
fmt.Printf("Debug logging directory '%s' doesn't exist, creating it\n", Datadir) |
|
|
|
|
os.Mkdir(Datadir, 0777) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func InitLogging (Datadir string, LogFile string, LogLevel int, DebugFile string) { |
|
|
|
|
var writer io.Writer |
|
|
|
|
if LogFile == "" { |
|
|
|
|
writer = os.Stdout |
|
|
|
|
} else { |
|
|
|
|
writer = openLogFile(Datadir, LogFile) |
|
|
|
|
} |
|
|
|
|
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.LogLevel(LogLevel))) |
|
|
|
|
if DebugFile != "" { |
|
|
|
|
writer = openLogFile(Datadir, DebugFile) |
|
|
|
|
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.DebugLevel)) |
|
|
|
|
} |
|
|
|
|
_, err := os.Stat(Datadir) |
|
|
|
|
if err != nil { |
|
|
|
|
if os.IsNotExist(err) { |
|
|
|
|
fmt.Printf("Debug logging directory '%s' doesn't exist, creating it\n", Datadir) |
|
|
|
|
os.Mkdir(Datadir, 0777) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) { |
|
|
|
|
var writer io.Writer |
|
|
|
|
if LogFile == "" { |
|
|
|
|
writer = os.Stdout |
|
|
|
|
} else { |
|
|
|
|
writer = openLogFile(Datadir, LogFile) |
|
|
|
|
} |
|
|
|
|
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.LogLevel(LogLevel))) |
|
|
|
|
if DebugFile != "" { |
|
|
|
|
writer = openLogFile(Datadir, DebugFile) |
|
|
|
|
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.DebugLevel)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func InitConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) { |
|
|
|
|
InitDataDir(Datadir) |
|
|
|
|
ethutil.ReadConfig(ConfigFile, Datadir, Identifier, EnvPrefix) |
|
|
|
|
ethutil.Config.Set("rpcport", "700") |
|
|
|
|
InitDataDir(Datadir) |
|
|
|
|
ethutil.ReadConfig(ConfigFile, Datadir, Identifier, EnvPrefix) |
|
|
|
|
ethutil.Config.Set("rpcport", "700") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func exit(status int) { |
|
|
|
|
ethlog.Flush() |
|
|
|
|
os.Exit(status) |
|
|
|
|
ethlog.Flush() |
|
|
|
|
os.Exit(status) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func NewEthereum(UseUPnP bool, OutboundPort string, MaxPeer int) *eth.Ethereum { |
|
|
|
|
ethereum, err := eth.New(eth.CapDefault, UseUPnP) |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Fatalln("eth start err:", err) |
|
|
|
|
} |
|
|
|
|
ethereum.Port = OutboundPort |
|
|
|
|
ethereum.MaxPeers = MaxPeer |
|
|
|
|
return ethereum |
|
|
|
|
ethereum, err := eth.New(eth.CapDefault, UseUPnP) |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Fatalln("eth start err:", err) |
|
|
|
|
} |
|
|
|
|
ethereum.Port = OutboundPort |
|
|
|
|
ethereum.MaxPeers = MaxPeer |
|
|
|
|
return ethereum |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) { |
|
|
|
|
logger.Infof("Starting Ethereum v%s", ethutil.Config.Ver) |
|
|
|
|
ethereum.Start(UseSeed) |
|
|
|
|
RegisterInterrupt(func(sig os.Signal) { |
|
|
|
|
ethereum.Stop() |
|
|
|
|
ethlog.Flush() |
|
|
|
|
}) |
|
|
|
|
logger.Infof("Starting Ethereum v%s", ethutil.Config.Ver) |
|
|
|
|
ethereum.Start(UseSeed) |
|
|
|
|
RegisterInterrupt(func(sig os.Signal) { |
|
|
|
|
ethereum.Stop() |
|
|
|
|
ethlog.Flush() |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func ShowGenesis(ethereum *eth.Ethereum) { |
|
|
|
|
logger.Infoln(ethereum.BlockChain().Genesis()) |
|
|
|
|
exit(0) |
|
|
|
|
logger.Infoln(ethereum.BlockChain().Genesis()) |
|
|
|
|
exit(0) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func KeyTasks(GenAddr bool, ImportKey string, ExportKey bool, NonInteractive bool) { |
|
|
|
|
switch { |
|
|
|
|
case GenAddr: |
|
|
|
|
if NonInteractive || confirm("This action overwrites your old private key.") { |
|
|
|
|
CreateKeyPair(true) |
|
|
|
|
} |
|
|
|
|
exit(0) |
|
|
|
|
case len(ImportKey) > 0: |
|
|
|
|
if NonInteractive || confirm("This action overwrites your old private key.") { |
|
|
|
|
// import should be from file
|
|
|
|
|
mnemonic := strings.Split(ImportKey, " ") |
|
|
|
|
if len(mnemonic) == 24 { |
|
|
|
|
logger.Infoln("Got mnemonic key, importing.") |
|
|
|
|
key := ethutil.MnemonicDecode(mnemonic) |
|
|
|
|
ImportPrivateKey(key) |
|
|
|
|
} else if len(mnemonic) == 1 { |
|
|
|
|
logger.Infoln("Got hex key, importing.") |
|
|
|
|
ImportPrivateKey(ImportKey) |
|
|
|
|
} else { |
|
|
|
|
logger.Errorln("Did not recognise format, exiting.") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
exit(0) |
|
|
|
|
case ExportKey: // this should be exporting to a filename
|
|
|
|
|
keyPair := ethutil.GetKeyRing().Get(0) |
|
|
|
|
fmt.Printf(` |
|
|
|
|
switch { |
|
|
|
|
case GenAddr: |
|
|
|
|
if NonInteractive || confirm("This action overwrites your old private key.") { |
|
|
|
|
CreateKeyPair(true) |
|
|
|
|
} |
|
|
|
|
exit(0) |
|
|
|
|
case len(ImportKey) > 0: |
|
|
|
|
if NonInteractive || confirm("This action overwrites your old private key.") { |
|
|
|
|
// import should be from file
|
|
|
|
|
mnemonic := strings.Split(ImportKey, " ") |
|
|
|
|
if len(mnemonic) == 24 { |
|
|
|
|
logger.Infoln("Got mnemonic key, importing.") |
|
|
|
|
key := ethutil.MnemonicDecode(mnemonic) |
|
|
|
|
ImportPrivateKey(key) |
|
|
|
|
} else if len(mnemonic) == 1 { |
|
|
|
|
logger.Infoln("Got hex key, importing.") |
|
|
|
|
ImportPrivateKey(ImportKey) |
|
|
|
|
} else { |
|
|
|
|
logger.Errorln("Did not recognise format, exiting.") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
exit(0) |
|
|
|
|
case ExportKey: // this should be exporting to a filename
|
|
|
|
|
keyPair := ethutil.GetKeyRing().Get(0) |
|
|
|
|
fmt.Printf(` |
|
|
|
|
Generating new address and keypair. |
|
|
|
|
Please keep your keys somewhere save. |
|
|
|
|
|
|
|
|
@ -169,61 +169,61 @@ pubk: %x |
|
|
|
|
save these words so you can restore your account later: %s |
|
|
|
|
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey) |
|
|
|
|
|
|
|
|
|
exit(0) |
|
|
|
|
default: |
|
|
|
|
// Creates a keypair if none exists
|
|
|
|
|
CreateKeyPair(false) |
|
|
|
|
} |
|
|
|
|
exit(0) |
|
|
|
|
default: |
|
|
|
|
// Creates a keypair if none exists
|
|
|
|
|
CreateKeyPair(false) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func StartRpc(ethereum *eth.Ethereum, RpcPort int) { |
|
|
|
|
var err error |
|
|
|
|
ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort) |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err) |
|
|
|
|
} else { |
|
|
|
|
go ethereum.RpcServer.Start() |
|
|
|
|
} |
|
|
|
|
var err error |
|
|
|
|
ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort) |
|
|
|
|
if err != nil { |
|
|
|
|
logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err) |
|
|
|
|
} else { |
|
|
|
|
go ethereum.RpcServer.Start() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var miner ethminer.Miner |
|
|
|
|
|
|
|
|
|
func StartMining(ethereum *eth.Ethereum) bool { |
|
|
|
|
if !ethereum.Mining { |
|
|
|
|
ethereum.Mining = true |
|
|
|
|
|
|
|
|
|
if ethutil.GetKeyRing().Len() == 0 { |
|
|
|
|
logger.Errorln("No address found, can't start mining") |
|
|
|
|
ethereum.Mining = false |
|
|
|
|
return true //????
|
|
|
|
|
} |
|
|
|
|
keyPair := ethutil.GetKeyRing().Get(0) |
|
|
|
|
addr := keyPair.Address() |
|
|
|
|
|
|
|
|
|
go func() { |
|
|
|
|
miner = ethminer.NewDefaultMiner(addr, ethereum) |
|
|
|
|
// Give it some time to connect with peers
|
|
|
|
|
time.Sleep(3 * time.Second) |
|
|
|
|
logger.Infoln("Miner started") |
|
|
|
|
miner := ethminer.NewDefaultMiner(addr, ethereum) |
|
|
|
|
miner.Start() |
|
|
|
|
}() |
|
|
|
|
RegisterInterrupt(func(os.Signal) { |
|
|
|
|
StopMining(ethereum) |
|
|
|
|
}) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
return false |
|
|
|
|
if !ethereum.Mining { |
|
|
|
|
ethereum.Mining = true |
|
|
|
|
|
|
|
|
|
if ethutil.GetKeyRing().Len() == 0 { |
|
|
|
|
logger.Errorln("No address found, can't start mining") |
|
|
|
|
ethereum.Mining = false |
|
|
|
|
return true //????
|
|
|
|
|
} |
|
|
|
|
keyPair := ethutil.GetKeyRing().Get(0) |
|
|
|
|
addr := keyPair.Address() |
|
|
|
|
|
|
|
|
|
go func() { |
|
|
|
|
miner = ethminer.NewDefaultMiner(addr, ethereum) |
|
|
|
|
// Give it some time to connect with peers
|
|
|
|
|
time.Sleep(3 * time.Second) |
|
|
|
|
logger.Infoln("Miner started") |
|
|
|
|
miner := ethminer.NewDefaultMiner(addr, ethereum) |
|
|
|
|
miner.Start() |
|
|
|
|
}() |
|
|
|
|
RegisterInterrupt(func(os.Signal) { |
|
|
|
|
StopMining(ethereum) |
|
|
|
|
}) |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func StopMining(ethereum *eth.Ethereum) bool { |
|
|
|
|
if ethereum.Mining { |
|
|
|
|
miner.Stop() |
|
|
|
|
logger.Infoln("Miner stopped") |
|
|
|
|
ethereum.Mining = false |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
return false |
|
|
|
|
if ethereum.Mining { |
|
|
|
|
miner.Stop() |
|
|
|
|
logger.Infoln("Miner stopped") |
|
|
|
|
ethereum.Mining = false |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Replay block
|
|
|
|
|