cmd.go 5.9 KB
Newer Older
1 2 3
package utils

import (
zelig's avatar
zelig committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17
	"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"
18 19
)

20
var logger = ethlog.NewLogger("CLI")
zelig's avatar
zelig committed
21
var interruptCallbacks = []func(os.Signal){}
22

zelig's avatar
zelig committed
23
// Register interrupt handlers callbacks
24
func RegisterInterrupt(cb func(os.Signal)) {
zelig's avatar
zelig committed
25
	interruptCallbacks = append(interruptCallbacks, cb)
zelig's avatar
zelig committed
26 27 28 29
}

// go routine that call interrupt handlers in order of registering
func HandleInterrupt() {
zelig's avatar
zelig committed
30 31 32 33 34 35 36 37
	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)
		}
	}()
38 39
}

zelig's avatar
zelig committed
40
func RunInterruptCallbacks(sig os.Signal) {
zelig's avatar
zelig committed
41 42 43
	for _, cb := range interruptCallbacks {
		cb(sig)
	}
zelig's avatar
zelig committed
44 45
}

46
func AbsolutePath(Datadir string, filename string) string {
zelig's avatar
zelig committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
	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"
74
}
obscuren's avatar
obscuren committed
75

76
func InitDataDir(Datadir string) {
zelig's avatar
zelig committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
	_, 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))
	}
98
}
99

100
func InitConfig(ConfigFile string, Datadir string, Identifier string, EnvPrefix string) {
zelig's avatar
zelig committed
101 102 103
	InitDataDir(Datadir)
	ethutil.ReadConfig(ConfigFile, Datadir, Identifier, EnvPrefix)
	ethutil.Config.Set("rpcport", "700")
104
}
105

106
func exit(status int) {
zelig's avatar
zelig committed
107 108
	ethlog.Flush()
	os.Exit(status)
109
}
obscuren's avatar
obscuren committed
110

111
func NewEthereum(UseUPnP bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
zelig's avatar
zelig committed
112 113 114 115 116 117 118
	ethereum, err := eth.New(eth.CapDefault, UseUPnP)
	if err != nil {
		logger.Fatalln("eth start err:", err)
	}
	ethereum.Port = OutboundPort
	ethereum.MaxPeers = MaxPeer
	return ethereum
119
}
obscuren's avatar
obscuren committed
120

121
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
zelig's avatar
zelig committed
122 123 124 125 126 127
	logger.Infof("Starting Ethereum v%s", ethutil.Config.Ver)
	ethereum.Start(UseSeed)
	RegisterInterrupt(func(sig os.Signal) {
		ethereum.Stop()
		ethlog.Flush()
	})
128
}
obscuren's avatar
obscuren committed
129

130
func ShowGenesis(ethereum *eth.Ethereum) {
zelig's avatar
zelig committed
131 132
	logger.Infoln(ethereum.BlockChain().Genesis())
	exit(0)
133
}
obscuren's avatar
obscuren committed
134

135
func KeyTasks(GenAddr bool, ImportKey string, ExportKey bool, NonInteractive bool) {
zelig's avatar
zelig committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
	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(`
161 162 163 164 165 166 167 168 169 170 171
Generating new address and keypair.
Please keep your keys somewhere save.

++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey)

zelig's avatar
zelig committed
172 173 174 175 176
		exit(0)
	default:
		// Creates a keypair if none exists
		CreateKeyPair(false)
	}
177
}
obscuren's avatar
obscuren committed
178

179
func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
zelig's avatar
zelig committed
180 181 182 183 184 185 186
	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()
	}
obscuren's avatar
obscuren committed
187 188
}

189
var miner ethminer.Miner
obscuren's avatar
obscuren committed
190

191
func StartMining(ethereum *eth.Ethereum) bool {
zelig's avatar
zelig committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
	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)
207
			for !ethereum.IsUpToDate() {
208 209 210
				time.Sleep(5 * time.Second)
			}

zelig's avatar
zelig committed
211 212 213 214 215 216 217 218 219 220
			logger.Infoln("Miner started")
			miner := ethminer.NewDefaultMiner(addr, ethereum)
			miner.Start()
		}()
		RegisterInterrupt(func(os.Signal) {
			StopMining(ethereum)
		})
		return true
	}
	return false
221
}
obscuren's avatar
obscuren committed
222

223
func StopMining(ethereum *eth.Ethereum) bool {
zelig's avatar
zelig committed
224 225 226 227 228 229 230
	if ethereum.Mining {
		miner.Stop()
		logger.Infoln("Miner stopped")
		ethereum.Mining = false
		return true
	}
	return false
obscuren's avatar
obscuren committed
231
}
obscuren's avatar
obscuren committed
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

// Replay block
func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
	block := ethereum.BlockChain().GetBlock(hash)
	if block == nil {
		return fmt.Errorf("unknown block %x", hash)
	}

	parent := ethereum.BlockChain().GetBlock(block.PrevHash)

	_, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block)
	if err != nil {
		return err
	}

	return nil

}