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 }