github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/cmd/utils/cmd.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package utils contains internal helper functions for go-ethereum commands. 18 package utils 19 20 import ( 21 "bufio" 22 "fmt" 23 "io" 24 "math" 25 "math/big" 26 "os" 27 "os/signal" 28 "regexp" 29 "strings" 30 31 "github.com/ethereum/go-ethereum/common" 32 "github.com/ethereum/go-ethereum/core" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/eth" 35 "github.com/ethereum/go-ethereum/logger" 36 "github.com/ethereum/go-ethereum/logger/glog" 37 "github.com/ethereum/go-ethereum/params" 38 "github.com/ethereum/go-ethereum/rlp" 39 "github.com/peterh/liner" 40 ) 41 42 const ( 43 importBatchSize = 2500 44 ) 45 46 var interruptCallbacks = []func(os.Signal){} 47 48 func openLogFile(Datadir string, filename string) *os.File { 49 path := common.AbsolutePath(Datadir, filename) 50 file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) 51 if err != nil { 52 panic(fmt.Sprintf("error opening log file '%s': %v", filename, err)) 53 } 54 return file 55 } 56 57 func PromptConfirm(prompt string) (bool, error) { 58 var ( 59 input string 60 err error 61 ) 62 prompt = prompt + " [y/N] " 63 64 // if liner.TerminalSupported() { 65 // fmt.Println("term") 66 // lr := liner.NewLiner() 67 // defer lr.Close() 68 // input, err = lr.Prompt(prompt) 69 // } else { 70 fmt.Print(prompt) 71 input, err = bufio.NewReader(os.Stdin).ReadString('\n') 72 fmt.Println() 73 // } 74 75 if len(input) > 0 && strings.ToUpper(input[:1]) == "Y" { 76 return true, nil 77 } else { 78 return false, nil 79 } 80 81 return false, err 82 } 83 84 func PromptPassword(prompt string, warnTerm bool) (string, error) { 85 if liner.TerminalSupported() { 86 lr := liner.NewLiner() 87 defer lr.Close() 88 return lr.PasswordPrompt(prompt) 89 } 90 if warnTerm { 91 fmt.Println("!! Unsupported terminal, password will be echoed.") 92 } 93 fmt.Print(prompt) 94 input, err := bufio.NewReader(os.Stdin).ReadString('\n') 95 fmt.Println() 96 return input, err 97 } 98 99 func CheckLegalese(datadir string) { 100 // check "first run" 101 if !common.FileExist(datadir) { 102 r, _ := PromptConfirm(legalese) 103 if !r { 104 Fatalf("Must accept to continue. Shutting down...\n") 105 } 106 } 107 } 108 109 // Fatalf formats a message to standard error and exits the program. 110 // The message is also printed to standard output if standard error 111 // is redirected to a different file. 112 func Fatalf(format string, args ...interface{}) { 113 w := io.MultiWriter(os.Stdout, os.Stderr) 114 outf, _ := os.Stdout.Stat() 115 errf, _ := os.Stderr.Stat() 116 if outf != nil && errf != nil && os.SameFile(outf, errf) { 117 w = os.Stderr 118 } 119 fmt.Fprintf(w, "Fatal: "+format+"\n", args...) 120 logger.Flush() 121 os.Exit(1) 122 } 123 124 func StartEthereum(ethereum *eth.Ethereum) { 125 glog.V(logger.Info).Infoln("Starting", ethereum.Name()) 126 if err := ethereum.Start(); err != nil { 127 Fatalf("Error starting Ethereum: %v", err) 128 } 129 go func() { 130 sigc := make(chan os.Signal, 1) 131 signal.Notify(sigc, os.Interrupt) 132 defer signal.Stop(sigc) 133 <-sigc 134 glog.V(logger.Info).Infoln("Got interrupt, shutting down...") 135 go ethereum.Stop() 136 logger.Flush() 137 for i := 10; i > 0; i-- { 138 <-sigc 139 if i > 1 { 140 glog.V(logger.Info).Infoln("Already shutting down, please be patient.") 141 glog.V(logger.Info).Infoln("Interrupt", i-1, "more times to induce panic.") 142 } 143 } 144 glog.V(logger.Error).Infof("Force quitting: this might not end so well.") 145 panic("boom") 146 }() 147 } 148 149 func InitOlympic() { 150 params.DurationLimit = big.NewInt(8) 151 params.GenesisGasLimit = big.NewInt(3141592) 152 params.MinGasLimit = big.NewInt(125000) 153 params.MaximumExtraDataSize = big.NewInt(1024) 154 NetworkIdFlag.Value = 0 155 core.BlockReward = big.NewInt(1.5e+18) 156 core.ExpDiffPeriod = big.NewInt(math.MaxInt64) 157 } 158 159 func FormatTransactionData(data string) []byte { 160 d := common.StringToByteFunc(data, func(s string) (ret []byte) { 161 slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000) 162 for _, dataItem := range slice { 163 d := common.FormatData(dataItem) 164 ret = append(ret, d...) 165 } 166 return 167 }) 168 169 return d 170 } 171 172 func ImportChain(chain *core.ChainManager, fn string) error { 173 // Watch for Ctrl-C while the import is running. 174 // If a signal is received, the import will stop at the next batch. 175 interrupt := make(chan os.Signal, 1) 176 stop := make(chan struct{}) 177 signal.Notify(interrupt, os.Interrupt) 178 defer signal.Stop(interrupt) 179 defer close(interrupt) 180 go func() { 181 if _, ok := <-interrupt; ok { 182 glog.Info("caught interrupt during import, will stop at next batch") 183 } 184 close(stop) 185 }() 186 checkInterrupt := func() bool { 187 select { 188 case <-stop: 189 return true 190 default: 191 return false 192 } 193 } 194 195 glog.Infoln("Importing blockchain", fn) 196 fh, err := os.Open(fn) 197 if err != nil { 198 return err 199 } 200 defer fh.Close() 201 stream := rlp.NewStream(fh, 0) 202 203 // Run actual the import. 204 blocks := make(types.Blocks, importBatchSize) 205 n := 0 206 for batch := 0; ; batch++ { 207 // Load a batch of RLP blocks. 208 if checkInterrupt() { 209 return fmt.Errorf("interrupted") 210 } 211 i := 0 212 for ; i < importBatchSize; i++ { 213 var b types.Block 214 if err := stream.Decode(&b); err == io.EOF { 215 break 216 } else if err != nil { 217 return fmt.Errorf("at block %d: %v", n, err) 218 } 219 // don't import first block 220 if b.NumberU64() == 0 { 221 i-- 222 continue 223 } 224 blocks[i] = &b 225 n++ 226 } 227 if i == 0 { 228 break 229 } 230 // Import the batch. 231 if checkInterrupt() { 232 return fmt.Errorf("interrupted") 233 } 234 if hasAllBlocks(chain, blocks[:i]) { 235 glog.Infof("skipping batch %d, all blocks present [%x / %x]", 236 batch, blocks[0].Hash().Bytes()[:4], blocks[i-1].Hash().Bytes()[:4]) 237 continue 238 } 239 240 if _, err := chain.InsertChain(blocks[:i]); err != nil { 241 return fmt.Errorf("invalid block %d: %v", n, err) 242 } 243 } 244 return nil 245 } 246 247 func hasAllBlocks(chain *core.ChainManager, bs []*types.Block) bool { 248 for _, b := range bs { 249 if !chain.HasBlock(b.Hash()) { 250 return false 251 } 252 } 253 return true 254 } 255 256 func ExportChain(chainmgr *core.ChainManager, fn string) error { 257 glog.Infoln("Exporting blockchain to", fn) 258 fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 259 if err != nil { 260 return err 261 } 262 defer fh.Close() 263 if err := chainmgr.Export(fh); err != nil { 264 return err 265 } 266 glog.Infoln("Exported blockchain to", fn) 267 return nil 268 } 269 270 func ExportAppendChain(chainmgr *core.ChainManager, fn string, first uint64, last uint64) error { 271 glog.Infoln("Exporting blockchain to", fn) 272 // TODO verify mode perms 273 fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm) 274 if err != nil { 275 return err 276 } 277 defer fh.Close() 278 if err := chainmgr.ExportN(fh, first, last); err != nil { 279 return err 280 } 281 glog.Infoln("Exported blockchain to", fn) 282 return nil 283 }