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  }