cmd.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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. // Package utils contains internal helper functions for go-ethereum commands.
  17. package utils
  18. import (
  19. "fmt"
  20. "io"
  21. "os"
  22. "os/signal"
  23. "regexp"
  24. "github.com/ethereum/go-ethereum/common"
  25. "github.com/ethereum/go-ethereum/core"
  26. "github.com/ethereum/go-ethereum/core/types"
  27. "github.com/ethereum/go-ethereum/internal/debug"
  28. "github.com/ethereum/go-ethereum/logger"
  29. "github.com/ethereum/go-ethereum/logger/glog"
  30. "github.com/ethereum/go-ethereum/node"
  31. "github.com/ethereum/go-ethereum/rlp"
  32. )
  33. const (
  34. importBatchSize = 2500
  35. )
  36. func openLogFile(Datadir string, filename string) *os.File {
  37. path := common.AbsolutePath(Datadir, filename)
  38. file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  39. if err != nil {
  40. panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
  41. }
  42. return file
  43. }
  44. // Fatalf formats a message to standard error and exits the program.
  45. // The message is also printed to standard output if standard error
  46. // is redirected to a different file.
  47. func Fatalf(format string, args ...interface{}) {
  48. w := io.MultiWriter(os.Stdout, os.Stderr)
  49. outf, _ := os.Stdout.Stat()
  50. errf, _ := os.Stderr.Stat()
  51. if outf != nil && errf != nil && os.SameFile(outf, errf) {
  52. w = os.Stderr
  53. }
  54. fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
  55. logger.Flush()
  56. os.Exit(1)
  57. }
  58. func StartNode(stack *node.Node) {
  59. if err := stack.Start(); err != nil {
  60. Fatalf("Error starting protocol stack: %v", err)
  61. }
  62. go func() {
  63. sigc := make(chan os.Signal, 1)
  64. signal.Notify(sigc, os.Interrupt)
  65. defer signal.Stop(sigc)
  66. <-sigc
  67. glog.V(logger.Info).Infoln("Got interrupt, shutting down...")
  68. go stack.Stop()
  69. logger.Flush()
  70. for i := 10; i > 0; i-- {
  71. <-sigc
  72. if i > 1 {
  73. glog.V(logger.Info).Infoln("Already shutting down, please be patient.")
  74. glog.V(logger.Info).Infoln("Interrupt", i-1, "more times to induce panic.")
  75. }
  76. }
  77. glog.V(logger.Error).Infof("Force quitting: this might not end so well.")
  78. debug.LoudPanic("boom")
  79. }()
  80. }
  81. func FormatTransactionData(data string) []byte {
  82. d := common.StringToByteFunc(data, func(s string) (ret []byte) {
  83. slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
  84. for _, dataItem := range slice {
  85. d := common.FormatData(dataItem)
  86. ret = append(ret, d...)
  87. }
  88. return
  89. })
  90. return d
  91. }
  92. func ImportChain(chain *core.BlockChain, fn string) error {
  93. // Watch for Ctrl-C while the import is running.
  94. // If a signal is received, the import will stop at the next batch.
  95. interrupt := make(chan os.Signal, 1)
  96. stop := make(chan struct{})
  97. signal.Notify(interrupt, os.Interrupt)
  98. defer signal.Stop(interrupt)
  99. defer close(interrupt)
  100. go func() {
  101. if _, ok := <-interrupt; ok {
  102. glog.Info("caught interrupt during import, will stop at next batch")
  103. }
  104. close(stop)
  105. }()
  106. checkInterrupt := func() bool {
  107. select {
  108. case <-stop:
  109. return true
  110. default:
  111. return false
  112. }
  113. }
  114. glog.Infoln("Importing blockchain", fn)
  115. fh, err := os.Open(fn)
  116. if err != nil {
  117. return err
  118. }
  119. defer fh.Close()
  120. stream := rlp.NewStream(fh, 0)
  121. // Run actual the import.
  122. blocks := make(types.Blocks, importBatchSize)
  123. n := 0
  124. for batch := 0; ; batch++ {
  125. // Load a batch of RLP blocks.
  126. if checkInterrupt() {
  127. return fmt.Errorf("interrupted")
  128. }
  129. i := 0
  130. for ; i < importBatchSize; i++ {
  131. var b types.Block
  132. if err := stream.Decode(&b); err == io.EOF {
  133. break
  134. } else if err != nil {
  135. return fmt.Errorf("at block %d: %v", n, err)
  136. }
  137. // don't import first block
  138. if b.NumberU64() == 0 {
  139. i--
  140. continue
  141. }
  142. blocks[i] = &b
  143. n++
  144. }
  145. if i == 0 {
  146. break
  147. }
  148. // Import the batch.
  149. if checkInterrupt() {
  150. return fmt.Errorf("interrupted")
  151. }
  152. if hasAllBlocks(chain, blocks[:i]) {
  153. glog.Infof("skipping batch %d, all blocks present [%x / %x]",
  154. batch, blocks[0].Hash().Bytes()[:4], blocks[i-1].Hash().Bytes()[:4])
  155. continue
  156. }
  157. if _, err := chain.InsertChain(blocks[:i]); err != nil {
  158. return fmt.Errorf("invalid block %d: %v", n, err)
  159. }
  160. }
  161. return nil
  162. }
  163. func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
  164. for _, b := range bs {
  165. if !chain.HasBlock(b.Hash()) {
  166. return false
  167. }
  168. }
  169. return true
  170. }
  171. func ExportChain(blockchain *core.BlockChain, fn string) error {
  172. glog.Infoln("Exporting blockchain to", fn)
  173. fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
  174. if err != nil {
  175. return err
  176. }
  177. defer fh.Close()
  178. if err := blockchain.Export(fh); err != nil {
  179. return err
  180. }
  181. glog.Infoln("Exported blockchain to", fn)
  182. return nil
  183. }
  184. func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
  185. glog.Infoln("Exporting blockchain to", fn)
  186. // TODO verify mode perms
  187. fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
  188. if err != nil {
  189. return err
  190. }
  191. defer fh.Close()
  192. if err := blockchain.ExportN(fh, first, last); err != nil {
  193. return err
  194. }
  195. glog.Infoln("Exported blockchain to", fn)
  196. return nil
  197. }