github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/cmd/utils/cmd.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2014 Go Ethereum作者
    10  //此文件是Go以太坊的一部分。
    11  //
    12  //Go以太坊是免费软件:您可以重新发布和/或修改它
    13  //根据GNU通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊的分布希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU通用公共许可证了解更多详细信息。
    21  //
    22  //你应该已经收到一份GNU通用公共许可证的副本
    23  //一起去以太坊吧。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  //
    26  package utils
    27  
    28  import (
    29  	"compress/gzip"
    30  	"fmt"
    31  	"io"
    32  	"os"
    33  	"os/signal"
    34  	"runtime"
    35  	"strings"
    36  	"syscall"
    37  
    38  	"github.com/ethereum/go-ethereum/common"
    39  	"github.com/ethereum/go-ethereum/core"
    40  	"github.com/ethereum/go-ethereum/core/rawdb"
    41  	"github.com/ethereum/go-ethereum/core/types"
    42  	"github.com/ethereum/go-ethereum/crypto"
    43  	"github.com/ethereum/go-ethereum/ethdb"
    44  	"github.com/ethereum/go-ethereum/internal/debug"
    45  	"github.com/ethereum/go-ethereum/log"
    46  	"github.com/ethereum/go-ethereum/node"
    47  	"github.com/ethereum/go-ethereum/rlp"
    48  )
    49  
    50  const (
    51  	importBatchSize = 2500
    52  )
    53  
    54  //fatalf将消息格式化为标准错误并退出程序。
    55  //如果标准错误,消息也会打印到标准输出。
    56  //已重定向到其他文件。
    57  func Fatalf(format string, args ...interface{}) {
    58  	w := io.MultiWriter(os.Stdout, os.Stderr)
    59  	if runtime.GOOS == "windows" {
    60  //
    61  //
    62  		w = os.Stdout
    63  	} else {
    64  		outf, _ := os.Stdout.Stat()
    65  		errf, _ := os.Stderr.Stat()
    66  		if outf != nil && errf != nil && os.SameFile(outf, errf) {
    67  			w = os.Stderr
    68  		}
    69  	}
    70  	fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
    71  	os.Exit(1)
    72  }
    73  
    74  func StartNode(stack *node.Node) {
    75  	if err := stack.Start(); err != nil {
    76  		Fatalf("Error starting protocol stack: %v", err)
    77  	}
    78  	go func() {
    79  		sigc := make(chan os.Signal, 1)
    80  		signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
    81  		defer signal.Stop(sigc)
    82  		<-sigc
    83  		log.Info("Got interrupt, shutting down...")
    84  		go stack.Stop()
    85  		for i := 10; i > 0; i-- {
    86  			<-sigc
    87  			if i > 1 {
    88  				log.Warn("Already shutting down, interrupt more to panic.", "times", i-1)
    89  			}
    90  		}
    91  debug.Exit() //确保刷新跟踪和CPU配置文件数据。
    92  		debug.LoudPanic("boom")
    93  	}()
    94  }
    95  
    96  func ImportChain(chain *core.BlockChain, fn string) error {
    97  //当导入正在运行时,请注意ctrl-c。
    98  //如果收到信号,导入将在下一批停止。
    99  	interrupt := make(chan os.Signal, 1)
   100  	stop := make(chan struct{})
   101  	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
   102  	defer signal.Stop(interrupt)
   103  	defer close(interrupt)
   104  	go func() {
   105  		if _, ok := <-interrupt; ok {
   106  			log.Info("Interrupted during import, stopping at next batch")
   107  		}
   108  		close(stop)
   109  	}()
   110  	checkInterrupt := func() bool {
   111  		select {
   112  		case <-stop:
   113  			return true
   114  		default:
   115  			return false
   116  		}
   117  	}
   118  
   119  	log.Info("Importing blockchain", "file", fn)
   120  
   121  //打开文件句柄并可能打开gzip流
   122  	fh, err := os.Open(fn)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	defer fh.Close()
   127  
   128  	var reader io.Reader = fh
   129  	if strings.HasSuffix(fn, ".gz") {
   130  		if reader, err = gzip.NewReader(reader); err != nil {
   131  			return err
   132  		}
   133  	}
   134  	stream := rlp.NewStream(reader, 0)
   135  
   136  //实际运行导入。
   137  	blocks := make(types.Blocks, importBatchSize)
   138  	n := 0
   139  	for batch := 0; ; batch++ {
   140  //加载一批RLP块。
   141  		if checkInterrupt() {
   142  			return fmt.Errorf("interrupted")
   143  		}
   144  		i := 0
   145  		for ; i < importBatchSize; i++ {
   146  			var b types.Block
   147  			if err := stream.Decode(&b); err == io.EOF {
   148  				break
   149  			} else if err != nil {
   150  				return fmt.Errorf("at block %d: %v", n, err)
   151  			}
   152  //不导入第一个块
   153  			if b.NumberU64() == 0 {
   154  				i--
   155  				continue
   156  			}
   157  			blocks[i] = &b
   158  			n++
   159  		}
   160  		if i == 0 {
   161  			break
   162  		}
   163  //
   164  		if checkInterrupt() {
   165  			return fmt.Errorf("interrupted")
   166  		}
   167  		missing := missingBlocks(chain, blocks[:i])
   168  		if len(missing) == 0 {
   169  			log.Info("Skipping batch as all blocks present", "batch", batch, "first", blocks[0].Hash(), "last", blocks[i-1].Hash())
   170  			continue
   171  		}
   172  		if _, err := chain.InsertChain(missing); err != nil {
   173  			return fmt.Errorf("invalid block %d: %v", n, err)
   174  		}
   175  	}
   176  	return nil
   177  }
   178  
   179  func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block {
   180  	head := chain.CurrentBlock()
   181  	for i, block := range blocks {
   182  //
   183  		if head.NumberU64() > block.NumberU64() {
   184  			if !chain.HasBlock(block.Hash(), block.NumberU64()) {
   185  				return blocks[i:]
   186  			}
   187  			continue
   188  		}
   189  //如果我们在链头之上,状态可用性是必须的
   190  		if !chain.HasBlockAndState(block.Hash(), block.NumberU64()) {
   191  			return blocks[i:]
   192  		}
   193  	}
   194  	return nil
   195  }
   196  
   197  //exportchain将区块链导出到指定文件中,截断任何数据
   198  //
   199  func ExportChain(blockchain *core.BlockChain, fn string) error {
   200  	log.Info("Exporting blockchain", "file", fn)
   201  
   202  //
   203  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   204  	if err != nil {
   205  		return err
   206  	}
   207  	defer fh.Close()
   208  
   209  	var writer io.Writer = fh
   210  	if strings.HasSuffix(fn, ".gz") {
   211  		writer = gzip.NewWriter(writer)
   212  		defer writer.(*gzip.Writer).Close()
   213  	}
   214  //遍历块并导出它们
   215  	if err := blockchain.Export(writer); err != nil {
   216  		return err
   217  	}
   218  	log.Info("Exported blockchain", "file", fn)
   219  
   220  	return nil
   221  }
   222  
   223  //
   224  //文件中已存在数据。
   225  func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error {
   226  	log.Info("Exporting blockchain", "file", fn)
   227  
   228  //打开文件句柄并可能使用gzip流进行包装
   229  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
   230  	if err != nil {
   231  		return err
   232  	}
   233  	defer fh.Close()
   234  
   235  	var writer io.Writer = fh
   236  	if strings.HasSuffix(fn, ".gz") {
   237  		writer = gzip.NewWriter(writer)
   238  		defer writer.(*gzip.Writer).Close()
   239  	}
   240  //遍历块并导出它们
   241  	if err := blockchain.ExportN(writer, first, last); err != nil {
   242  		return err
   243  	}
   244  	log.Info("Exported blockchain to", "file", fn)
   245  	return nil
   246  }
   247  
   248  //importpreimages将一批导出的哈希预映像导入数据库。
   249  func ImportPreimages(db *ethdb.LDBDatabase, fn string) error {
   250  	log.Info("Importing preimages", "file", fn)
   251  
   252  //打开文件句柄并可能打开gzip流
   253  	fh, err := os.Open(fn)
   254  	if err != nil {
   255  		return err
   256  	}
   257  	defer fh.Close()
   258  
   259  	var reader io.Reader = fh
   260  	if strings.HasSuffix(fn, ".gz") {
   261  		if reader, err = gzip.NewReader(reader); err != nil {
   262  			return err
   263  		}
   264  	}
   265  	stream := rlp.NewStream(reader, 0)
   266  
   267  //批量导入预映像以防止磁盘损坏
   268  	preimages := make(map[common.Hash][]byte)
   269  
   270  	for {
   271  //阅读下一个条目并确保它不是垃圾
   272  		var blob []byte
   273  
   274  		if err := stream.Decode(&blob); err != nil {
   275  			if err == io.EOF {
   276  				break
   277  			}
   278  			return err
   279  		}
   280  //积累预映像并在收集足够的WS时刷新
   281  		preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob)
   282  		if len(preimages) > 1024 {
   283  			rawdb.WritePreimages(db, 0, preimages)
   284  			preimages = make(map[common.Hash][]byte)
   285  		}
   286  	}
   287  //刷新上一批预映像数据
   288  	if len(preimages) > 0 {
   289  		rawdb.WritePreimages(db, 0, preimages)
   290  	}
   291  	return nil
   292  }
   293  
   294  //exportpreimages将所有已知的哈希preimages导出到指定的文件中,
   295  //
   296  func ExportPreimages(db *ethdb.LDBDatabase, fn string) error {
   297  	log.Info("Exporting preimages", "file", fn)
   298  
   299  //打开文件句柄并可能使用gzip流进行包装
   300  	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   301  	if err != nil {
   302  		return err
   303  	}
   304  	defer fh.Close()
   305  
   306  	var writer io.Writer = fh
   307  	if strings.HasSuffix(fn, ".gz") {
   308  		writer = gzip.NewWriter(writer)
   309  		defer writer.(*gzip.Writer).Close()
   310  	}
   311  //迭代预映像并导出它们
   312  	it := db.NewIteratorWithPrefix([]byte("secure-key-"))
   313  	for it.Next() {
   314  		if err := rlp.Encode(writer, it.Value()); err != nil {
   315  			return err
   316  		}
   317  	}
   318  	log.Info("Exported preimages", "file", fn)
   319  	return nil
   320  }