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

import (
zelig's avatar
zelig committed
4
	"fmt"
5 6 7 8 9 10
	"io"
	"log"
	"os"
	"os/signal"
	"path"
	"path/filepath"
obscuren's avatar
obscuren committed
11
	"regexp"
12 13 14 15
	"runtime"
	"time"

	"bitbucket.org/kardianos/osext"
16
	"github.com/ethereum/go-ethereum"
obscuren's avatar
obscuren committed
17
	"github.com/ethereum/go-ethereum/crypto"
18 19
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/ethutil"
obscuren's avatar
obscuren committed
20
	"github.com/ethereum/go-ethereum/logger"
obscuren's avatar
obscuren committed
21
	"github.com/ethereum/go-ethereum/miner"
22
	"github.com/ethereum/go-ethereum/rpc"
obscuren's avatar
obscuren committed
23
	"github.com/ethereum/go-ethereum/wire"
24
	"github.com/ethereum/go-ethereum/xeth"
25 26
)

obscuren's avatar
obscuren committed
27
var clilogger = logger.NewLogger("CLI")
zelig's avatar
zelig committed
28
var interruptCallbacks = []func(os.Signal){}
29

zelig's avatar
zelig committed
30
// Register interrupt handlers callbacks
31
func RegisterInterrupt(cb func(os.Signal)) {
zelig's avatar
zelig committed
32
	interruptCallbacks = append(interruptCallbacks, cb)
zelig's avatar
zelig committed
33 34 35 36
}

// go routine that call interrupt handlers in order of registering
func HandleInterrupt() {
zelig's avatar
zelig committed
37 38 39 40
	c := make(chan os.Signal, 1)
	go func() {
		signal.Notify(c, os.Interrupt)
		for sig := range c {
obscuren's avatar
obscuren committed
41
			clilogger.Errorf("Shutting down (%v) ... \n", sig)
zelig's avatar
zelig committed
42 43 44
			RunInterruptCallbacks(sig)
		}
	}()
45 46
}

zelig's avatar
zelig committed
47
func RunInterruptCallbacks(sig os.Signal) {
zelig's avatar
zelig committed
48 49 50
	for _, cb := range interruptCallbacks {
		cb(sig)
	}
zelig's avatar
zelig committed
51 52
}

53
func AbsolutePath(Datadir string, filename string) string {
zelig's avatar
zelig committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
	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"
81
}
obscuren's avatar
obscuren committed
82

obscuren's avatar
obscuren committed
83 84 85 86 87 88 89 90 91 92
func DBSanityCheck(db ethutil.Database) error {
	d, _ := db.Get([]byte("ProtocolVersion"))
	protov := ethutil.NewValue(d).Uint()
	if protov != eth.ProtocolVersion && protov != 0 {
		return fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, eth.ProtocolVersion, ethutil.Config.ExecPath+"/database")
	}

	return nil
}

93
func InitDataDir(Datadir string) {
zelig's avatar
zelig committed
94 95 96
	_, err := os.Stat(Datadir)
	if err != nil {
		if os.IsNotExist(err) {
97
			fmt.Printf("Data directory '%s' doesn't exist, creating it\n", Datadir)
zelig's avatar
zelig committed
98 99 100 101 102
			os.Mkdir(Datadir, 0777)
		}
	}
}

obscuren's avatar
obscuren committed
103
func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) logger.LogSystem {
zelig's avatar
zelig committed
104 105 106 107 108 109
	var writer io.Writer
	if LogFile == "" {
		writer = os.Stdout
	} else {
		writer = openLogFile(Datadir, LogFile)
	}
110

obscuren's avatar
obscuren committed
111 112
	sys := logger.NewStdLogSystem(writer, log.LstdFlags, logger.LogLevel(LogLevel))
	logger.AddLogSystem(sys)
zelig's avatar
zelig committed
113 114
	if DebugFile != "" {
		writer = openLogFile(Datadir, DebugFile)
obscuren's avatar
obscuren committed
115
		logger.AddLogSystem(logger.NewStdLogSystem(writer, log.LstdFlags, logger.DebugLevel))
zelig's avatar
zelig committed
116
	}
117 118

	return sys
119
}
120

obscuren's avatar
obscuren committed
121
func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
zelig's avatar
zelig committed
122
	InitDataDir(Datadir)
obscuren's avatar
obscuren committed
123 124 125 126
	cfg := ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
	cfg.VmType = vmType

	return cfg
127
}
128

129 130 131
func exit(err error) {
	status := 0
	if err != nil {
obscuren's avatar
obscuren committed
132
		clilogger.Errorln("Fatal: ", err)
133 134
		status = 1
	}
obscuren's avatar
obscuren committed
135
	logger.Flush()
zelig's avatar
zelig committed
136
	os.Exit(status)
137
}
obscuren's avatar
obscuren committed
138

139 140 141 142 143 144 145 146
func NewDatabase() ethutil.Database {
	db, err := ethdb.NewLDBDatabase("database")
	if err != nil {
		exit(err)
	}
	return db
}

obscuren's avatar
obscuren committed
147
func NewClientIdentity(clientIdentifier, version, customIdentifier string) *wire.SimpleClientIdentity {
obscuren's avatar
obscuren committed
148
	clilogger.Infoln("identity created")
obscuren's avatar
obscuren committed
149
	return wire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
zelig's avatar
zelig committed
150 151
}

obscuren's avatar
obscuren committed
152
func NewEthereum(db ethutil.Database, clientIdentity wire.ClientIdentity, keyManager *crypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
zelig's avatar
zelig committed
153
	ethereum, err := eth.New(db, clientIdentity, keyManager, eth.CapDefault, usePnp)
zelig's avatar
zelig committed
154
	if err != nil {
obscuren's avatar
obscuren committed
155
		clilogger.Fatalln("eth start err:", err)
zelig's avatar
zelig committed
156 157 158 159
	}
	ethereum.Port = OutboundPort
	ethereum.MaxPeers = MaxPeer
	return ethereum
160
}
obscuren's avatar
obscuren committed
161

162
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
obscuren's avatar
obscuren committed
163
	clilogger.Infof("Starting %s", ethereum.ClientIdentity())
zelig's avatar
zelig committed
164 165 166
	ethereum.Start(UseSeed)
	RegisterInterrupt(func(sig os.Signal) {
		ethereum.Stop()
obscuren's avatar
obscuren committed
167
		logger.Flush()
zelig's avatar
zelig committed
168
	})
169
}
obscuren's avatar
obscuren committed
170

171
func ShowGenesis(ethereum *eth.Ethereum) {
obscuren's avatar
obscuren committed
172
	clilogger.Infoln(ethereum.ChainManager().Genesis())
173
	exit(nil)
174
}
obscuren's avatar
obscuren committed
175

obscuren's avatar
obscuren committed
176 177
func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *crypto.KeyManager {
	var keyManager *crypto.KeyManager
178 179
	switch {
	case KeyStore == "db":
obscuren's avatar
obscuren committed
180
		keyManager = crypto.NewDBKeyManager(db)
181
	case KeyStore == "file":
obscuren's avatar
obscuren committed
182
		keyManager = crypto.NewFileKeyManager(Datadir)
183 184 185 186 187 188
	default:
		exit(fmt.Errorf("unknown keystore type: %s", KeyStore))
	}
	return keyManager
}

189 190 191 192 193 194
func DefaultAssetPath() string {
	var assetPath string
	// If the current working directory is the go-ethereum dir
	// assume a debug build and use the source directory as
	// asset directory.
	pwd, _ := os.Getwd()
195
	if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist") {
196 197 198 199 200 201 202 203
		assetPath = path.Join(pwd, "assets")
	} else {
		switch runtime.GOOS {
		case "darwin":
			// Get Binary Directory
			exedir, _ := osext.ExecutableFolder()
			assetPath = filepath.Join(exedir, "../Resources")
		case "linux":
204
			assetPath = "/usr/share/mist"
205 206 207 208 209 210 211 212
		case "windows":
			assetPath = "./assets"
		default:
			assetPath = "."
		}
	}
	return assetPath
}
213

obscuren's avatar
obscuren committed
214
func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
215

216
	var err error
zelig's avatar
zelig committed
217 218 219
	switch {
	case GenAddr:
		if NonInteractive || confirm("This action overwrites your old private key.") {
220
			err = keyManager.Init(KeyRing, 0, true)
zelig's avatar
zelig committed
221
		}
222 223
		exit(err)
	case len(SecretFile) > 0:
obscuren's avatar
obscuren committed
224 225
		SecretFile = ethutil.ExpandHomePath(SecretFile)

zelig's avatar
zelig committed
226
		if NonInteractive || confirm("This action overwrites your old private key.") {
227
			err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile)
zelig's avatar
zelig committed
228
		}
229 230 231 232 233 234 235
		exit(err)
	case len(ExportDir) > 0:
		err = keyManager.Init(KeyRing, 0, false)
		if err == nil {
			err = keyManager.Export(ExportDir)
		}
		exit(err)
zelig's avatar
zelig committed
236 237
	default:
		// Creates a keypair if none exists
238 239 240 241
		err = keyManager.Init(KeyRing, 0, false)
		if err != nil {
			exit(err)
		}
zelig's avatar
zelig committed
242
	}
243
}
obscuren's avatar
obscuren committed
244

245
func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
zelig's avatar
zelig committed
246
	var err error
247
	ethereum.RpcServer, err = rpc.NewJsonRpcServer(xeth.NewJSXEth(ethereum), RpcPort)
zelig's avatar
zelig committed
248
	if err != nil {
obscuren's avatar
obscuren committed
249
		clilogger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
zelig's avatar
zelig committed
250 251 252
	} else {
		go ethereum.RpcServer.Start()
	}
obscuren's avatar
obscuren committed
253 254
}

obscuren's avatar
obscuren committed
255
var gminer *miner.Miner
obscuren's avatar
obscuren committed
256

obscuren's avatar
obscuren committed
257 258
func GetMiner() *miner.Miner {
	return gminer
Maran's avatar
Maran committed
259
}
obscuren's avatar
obscuren committed
260

261
func StartMining(ethereum *eth.Ethereum) bool {
zelig's avatar
zelig committed
262 263
	if !ethereum.Mining {
		ethereum.Mining = true
264
		addr := ethereum.KeyManager().Address()
zelig's avatar
zelig committed
265 266

		go func() {
obscuren's avatar
obscuren committed
267
			clilogger.Infoln("Start mining")
obscuren's avatar
obscuren committed
268
			if gminer == nil {
269
				gminer = miner.New(addr, ethereum)
270
			}
zelig's avatar
zelig committed
271 272
			// Give it some time to connect with peers
			time.Sleep(3 * time.Second)
273
			for !ethereum.IsUpToDate() {
274 275
				time.Sleep(5 * time.Second)
			}
obscuren's avatar
obscuren committed
276
			gminer.Start()
zelig's avatar
zelig committed
277 278 279 280 281 282 283
		}()
		RegisterInterrupt(func(os.Signal) {
			StopMining(ethereum)
		})
		return true
	}
	return false
284
}
obscuren's avatar
obscuren committed
285

obscuren's avatar
obscuren committed
286 287 288 289 290 291 292 293 294 295 296 297 298
func FormatTransactionData(data string) []byte {
	d := ethutil.StringToByteFunc(data, func(s string) (ret []byte) {
		slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
		for _, dataItem := range slice {
			d := ethutil.FormatData(dataItem)
			ret = append(ret, d...)
		}
		return
	})

	return d
}

299
func StopMining(ethereum *eth.Ethereum) bool {
obscuren's avatar
obscuren committed
300 301
	if ethereum.Mining && gminer != nil {
		gminer.Stop()
obscuren's avatar
obscuren committed
302
		clilogger.Infoln("Stopped mining")
zelig's avatar
zelig committed
303
		ethereum.Mining = false
304

zelig's avatar
zelig committed
305 306
		return true
	}
307

zelig's avatar
zelig committed
308
	return false
obscuren's avatar
obscuren committed
309
}
obscuren's avatar
obscuren committed
310 311 312

// Replay block
func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
313
	block := ethereum.ChainManager().GetBlock(hash)
obscuren's avatar
obscuren committed
314 315 316 317
	if block == nil {
		return fmt.Errorf("unknown block %x", hash)
	}

318
	parent := ethereum.ChainManager().GetBlock(block.PrevHash)
obscuren's avatar
obscuren committed
319

obscuren's avatar
obscuren committed
320
	_, err := ethereum.BlockManager().ApplyDiff(parent.State(), parent, block)
obscuren's avatar
obscuren committed
321 322 323 324 325 326 327
	if err != nil {
		return err
	}

	return nil

}