github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/utilities/utils/cmd.go (about) 1 package utils 2 3 import ( 4 "compress/gzip" 5 "fmt" 6 "io" 7 "os" 8 "os/signal" 9 "runtime" 10 "strings" 11 "syscall" 12 13 "github.com/neatlab/neatio/chain/consensus" 14 neatptc "github.com/neatlab/neatio/neatptc" 15 "gopkg.in/urfave/cli.v1" 16 17 "github.com/neatlab/neatio/chain/core" 18 "github.com/neatlab/neatio/chain/core/rawdb" 19 "github.com/neatlab/neatio/chain/core/types" 20 "github.com/neatlab/neatio/chain/log" 21 "github.com/neatlab/neatio/neatdb" 22 "github.com/neatlab/neatio/network/node" 23 "github.com/neatlab/neatio/utilities/common" 24 "github.com/neatlab/neatio/utilities/crypto" 25 "github.com/neatlab/neatio/utilities/rlp" 26 ) 27 28 const ( 29 importBatchSize = 2500 30 ) 31 32 func Fatalf(format string, args ...interface{}) { 33 w := io.MultiWriter(os.Stdout, os.Stderr) 34 if runtime.GOOS == "windows" { 35 36 w = os.Stdout 37 } else { 38 outf, _ := os.Stdout.Stat() 39 errf, _ := os.Stderr.Stat() 40 if outf != nil && errf != nil && os.SameFile(outf, errf) { 41 w = os.Stderr 42 } 43 } 44 fmt.Fprintf(w, "Fatal: "+format+"\n", args...) 45 os.Exit(1) 46 } 47 48 func StartNode(ctx *cli.Context, stack *node.Node) error { 49 if err := stack.Start1(); err != nil { 50 Fatalf("Error starting protocol stack: %v", err) 51 } 52 53 mining := false 54 var neatio *neatptc.NeatIO 55 if err := stack.Service(&neatio); err == nil { 56 if neatcon, ok := neatio.Engine().(consensus.NeatCon); ok { 57 mining = neatcon.ShouldStart() 58 if mining { 59 stack.GetLogger().Info("NeatCon Consensus Engine will be start shortly") 60 } 61 } 62 } 63 64 if mining || ctx.GlobalBool(DeveloperFlag.Name) { 65 stack.GetLogger().Info("Mine will be start shortly") 66 67 var neatio *neatptc.NeatIO 68 if err := stack.Service(&neatio); err != nil { 69 Fatalf("NEAT Blockchain service not running: %v", err) 70 } 71 72 if threads := ctx.GlobalInt(MinerThreadsFlag.Name); threads > 0 { 73 type threaded interface { 74 SetThreads(threads int) 75 } 76 if th, ok := neatio.Engine().(threaded); ok { 77 th.SetThreads(threads) 78 } 79 } 80 81 neatio.TxPool().SetGasPrice(GlobalBig(ctx, MinerGasPriceFlag.Name)) 82 if err := neatio.StartMining(true); err != nil { 83 Fatalf("Failed to start mining: %v", err) 84 } 85 } 86 87 return nil 88 } 89 90 func ImportChain(chain *core.BlockChain, fn string) error { 91 92 interrupt := make(chan os.Signal, 1) 93 stop := make(chan struct{}) 94 signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) 95 defer signal.Stop(interrupt) 96 defer close(interrupt) 97 go func() { 98 if _, ok := <-interrupt; ok { 99 log.Info("Interrupted during import, stopping at next batch") 100 } 101 close(stop) 102 }() 103 checkInterrupt := func() bool { 104 select { 105 case <-stop: 106 return true 107 default: 108 return false 109 } 110 } 111 112 log.Info("Importing blockchain", "file", fn) 113 fh, err := os.Open(fn) 114 if err != nil { 115 return err 116 } 117 defer fh.Close() 118 119 var reader io.Reader = fh 120 if strings.HasSuffix(fn, ".gz") { 121 if reader, err = gzip.NewReader(reader); err != nil { 122 return err 123 } 124 } 125 stream := rlp.NewStream(reader, 0) 126 127 blocks := make(types.Blocks, importBatchSize) 128 n := 0 129 for batch := 0; ; batch++ { 130 131 if checkInterrupt() { 132 return fmt.Errorf("interrupted") 133 } 134 i := 0 135 for ; i < importBatchSize; i++ { 136 var b types.Block 137 if err := stream.Decode(&b); err == io.EOF { 138 break 139 } else if err != nil { 140 return fmt.Errorf("at block %d: %v", n, err) 141 } 142 143 if b.NumberU64() == 0 { 144 i-- 145 continue 146 } 147 blocks[i] = &b 148 n++ 149 } 150 if i == 0 { 151 break 152 } 153 154 if checkInterrupt() { 155 return fmt.Errorf("interrupted") 156 } 157 missing := missingBlocks(chain, blocks[:i]) 158 if len(missing) == 0 { 159 log.Info("Skipping batch as all blocks present", "batch", batch, "first", blocks[0].Hash(), "last", blocks[i-1].Hash()) 160 continue 161 } 162 if _, err := chain.InsertChain(missing); err != nil { 163 return fmt.Errorf("invalid block %d: %v", n, err) 164 } 165 } 166 return nil 167 } 168 169 func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block { 170 head := chain.CurrentBlock() 171 for i, block := range blocks { 172 173 if head.NumberU64() > block.NumberU64() { 174 if !chain.HasBlock(block.Hash(), block.NumberU64()) { 175 return blocks[i:] 176 } 177 continue 178 } 179 180 if !chain.HasBlockAndState(block.Hash(), block.NumberU64()) { 181 return blocks[i:] 182 } 183 } 184 return nil 185 } 186 187 func ExportChain(blockchain *core.BlockChain, fn string) error { 188 log.Info("Exporting blockchain", "file", fn) 189 fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 190 if err != nil { 191 return err 192 } 193 defer fh.Close() 194 195 var writer io.Writer = fh 196 if strings.HasSuffix(fn, ".gz") { 197 writer = gzip.NewWriter(writer) 198 defer writer.(*gzip.Writer).Close() 199 } 200 201 if err := blockchain.Export(writer); err != nil { 202 return err 203 } 204 log.Info("Exported blockchain", "file", fn) 205 206 return nil 207 } 208 209 func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, last uint64) error { 210 log.Info("Exporting blockchain", "file", fn) 211 212 fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm) 213 if err != nil { 214 return err 215 } 216 defer fh.Close() 217 218 var writer io.Writer = fh 219 if strings.HasSuffix(fn, ".gz") { 220 writer = gzip.NewWriter(writer) 221 defer writer.(*gzip.Writer).Close() 222 } 223 224 if err := blockchain.ExportN(writer, first, last); err != nil { 225 return err 226 } 227 log.Info("Exported blockchain to", "file", fn) 228 return nil 229 } 230 231 func ImportPreimages(db neatdb.Database, fn string) error { 232 log.Info("Importing preimages", "file", fn) 233 234 fh, err := os.Open(fn) 235 if err != nil { 236 return err 237 } 238 defer fh.Close() 239 240 var reader io.Reader = fh 241 if strings.HasSuffix(fn, ".gz") { 242 if reader, err = gzip.NewReader(reader); err != nil { 243 return err 244 } 245 } 246 stream := rlp.NewStream(reader, 0) 247 248 preimages := make(map[common.Hash][]byte) 249 250 for { 251 252 var blob []byte 253 254 if err := stream.Decode(&blob); err != nil { 255 if err == io.EOF { 256 break 257 } 258 return err 259 } 260 261 preimages[crypto.Keccak256Hash(blob)] = common.CopyBytes(blob) 262 if len(preimages) > 1024 { 263 rawdb.WritePreimages(db, preimages) 264 preimages = make(map[common.Hash][]byte) 265 } 266 } 267 268 if len(preimages) > 0 { 269 rawdb.WritePreimages(db, preimages) 270 } 271 return nil 272 } 273 274 func ExportPreimages(db neatdb.Database, fn string) error { 275 log.Info("Exporting preimages", "file", fn) 276 277 fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 278 if err != nil { 279 return err 280 } 281 defer fh.Close() 282 283 var writer io.Writer = fh 284 if strings.HasSuffix(fn, ".gz") { 285 writer = gzip.NewWriter(writer) 286 defer writer.(*gzip.Writer).Close() 287 } 288 289 it := db.NewIteratorWithPrefix([]byte("secure-key-")) 290 defer it.Release() 291 292 for it.Next() { 293 if err := rlp.Encode(writer, it.Value()); err != nil { 294 return err 295 } 296 } 297 log.Info("Exported preimages", "file", fn) 298 return nil 299 }