github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/cmd/geth/chaincmd.go (about) 1 // Copyright 2015 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 main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "os" 23 "runtime" 24 "strconv" 25 "sync/atomic" 26 "time" 27 28 "github.com/ethereum/go-ethereum/cmd/utils" 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/console" 31 "github.com/ethereum/go-ethereum/core" 32 "github.com/ethereum/go-ethereum/core/state" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/ethdb" 35 "github.com/ethereum/go-ethereum/log" 36 "github.com/ethereum/go-ethereum/trie" 37 "github.com/syndtr/goleveldb/leveldb/util" 38 "gopkg.in/urfave/cli.v1" 39 ) 40 41 var ( 42 initCommand = cli.Command{ 43 Action: utils.MigrateFlags(initGenesis), 44 Name: "init", 45 Usage: "Bootstrap and initialize a new genesis block", 46 ArgsUsage: "<genesisPath>", 47 Flags: []cli.Flag{ 48 utils.DataDirFlag, 49 utils.LightModeFlag, 50 }, 51 Category: "BLOCKCHAIN COMMANDS", 52 Description: ` 53 The init command initializes a new genesis block and definition for the network. 54 This is a destructive action and changes the network in which you will be 55 participating. 56 57 It expects the genesis file as argument.`, 58 } 59 importCommand = cli.Command{ 60 Action: utils.MigrateFlags(importChain), 61 Name: "import", 62 Usage: "Import a blockchain file", 63 ArgsUsage: "<filename> (<filename 2> ... <filename N>) ", 64 Flags: []cli.Flag{ 65 utils.DataDirFlag, 66 utils.CacheFlag, 67 utils.LightModeFlag, 68 }, 69 Category: "BLOCKCHAIN COMMANDS", 70 Description: ` 71 The import command imports blocks from an RLP-encoded form. The form can be one file 72 with several RLP-encoded blocks, or several files can be used. 73 74 If only one file is used, import error will result in failure. If several files are used, 75 processing will proceed even if an individual RLP-file import failure occurs.`, 76 } 77 exportCommand = cli.Command{ 78 Action: utils.MigrateFlags(exportChain), 79 Name: "export", 80 Usage: "Export blockchain into file", 81 ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]", 82 Flags: []cli.Flag{ 83 utils.DataDirFlag, 84 utils.CacheFlag, 85 utils.LightModeFlag, 86 }, 87 Category: "BLOCKCHAIN COMMANDS", 88 Description: ` 89 Requires a first argument of the file to write to. 90 Optional second and third arguments control the first and 91 last block to write. In this mode, the file will be appended 92 if already existing.`, 93 } 94 removedbCommand = cli.Command{ 95 Action: utils.MigrateFlags(removeDB), 96 Name: "removedb", 97 Usage: "Remove blockchain and state databases", 98 ArgsUsage: " ", 99 Flags: []cli.Flag{ 100 utils.DataDirFlag, 101 utils.LightModeFlag, 102 }, 103 Category: "BLOCKCHAIN COMMANDS", 104 Description: ` 105 Remove blockchain and state databases`, 106 } 107 dumpCommand = cli.Command{ 108 Action: utils.MigrateFlags(dump), 109 Name: "dump", 110 Usage: "Dump a specific block from storage", 111 ArgsUsage: "[<blockHash> | <blockNum>]...", 112 Flags: []cli.Flag{ 113 utils.DataDirFlag, 114 utils.CacheFlag, 115 utils.LightModeFlag, 116 }, 117 Category: "BLOCKCHAIN COMMANDS", 118 Description: ` 119 The arguments are interpreted as block numbers or hashes. 120 Use "ethereum dump 0" to dump the genesis block.`, 121 } 122 ) 123 124 // initGenesis will initialise the given JSON format genesis file and writes it as 125 // the zero'd block (i.e. genesis) or will fail hard if it can't succeed. 126 // When geth init, initGenesis create 2 database into node direcotry, 127 // chaindata for full sync, lightchaindata for light sync 128 func initGenesis(ctx *cli.Context) error { //$BIN_PATH/geth --datadir $PROJ_PATH/node7/data init $SETUP_INFO_PATH/genesis.json 129 // Make sure we have a valid genesis JSON 130 genesisPath := ctx.Args().First() 131 if len(genesisPath) == 0 { 132 utils.Fatalf("Must supply path to genesis JSON file") 133 } 134 file, err := os.Open(genesisPath) 135 if err != nil { 136 utils.Fatalf("Failed to read genesis file: %v", err) 137 } 138 defer file.Close() 139 140 genesis := new(core.Genesis) 141 if err := json.NewDecoder(file).Decode(genesis); err != nil { 142 utils.Fatalf("invalid genesis file: %v", err) 143 } 144 // Open an initialise both full and light databases 145 stack := makeFullNode(ctx) 146 for _, name := range []string{"chaindata", "lightchaindata"} { 147 chaindb, err := stack.OpenDatabase(name, 0, 0) 148 if err != nil { 149 utils.Fatalf("Failed to open database: %v", err) 150 } 151 _, hash, err := core.SetupGenesisBlock(chaindb, genesis) 152 if err != nil { 153 utils.Fatalf("Failed to write genesis block: %v", err) 154 } 155 log.Info("Successfully wrote genesis state", "database", name, "hash", hash) 156 } 157 return nil 158 } 159 160 func importChain(ctx *cli.Context) error { 161 if len(ctx.Args()) < 1 { 162 utils.Fatalf("This command requires an argument.") 163 } 164 stack := makeFullNode(ctx) 165 chain, chainDb := utils.MakeChain(ctx, stack) 166 defer chainDb.Close() 167 168 // Start periodically gathering memory profiles 169 var peakMemAlloc, peakMemSys uint64 170 go func() { 171 stats := new(runtime.MemStats) 172 for { 173 runtime.ReadMemStats(stats) 174 if atomic.LoadUint64(&peakMemAlloc) < stats.Alloc { 175 atomic.StoreUint64(&peakMemAlloc, stats.Alloc) 176 } 177 if atomic.LoadUint64(&peakMemSys) < stats.Sys { 178 atomic.StoreUint64(&peakMemSys, stats.Sys) 179 } 180 time.Sleep(5 * time.Second) 181 } 182 }() 183 // Import the chain 184 start := time.Now() 185 186 if len(ctx.Args()) == 1 { 187 if err := utils.ImportChain(chain, ctx.Args().First()); err != nil { 188 utils.Fatalf("Import error: %v", err) 189 } 190 } else { 191 for _, arg := range ctx.Args() { 192 if err := utils.ImportChain(chain, arg); err != nil { 193 log.Error("Import error", "file", arg, "err", err) 194 } 195 } 196 } 197 198 fmt.Printf("Import done in %v.\n\n", time.Since(start)) 199 200 // Output pre-compaction stats mostly to see the import trashing 201 db := chainDb.(*ethdb.LDBDatabase) 202 203 stats, err := db.LDB().GetProperty("leveldb.stats") 204 if err != nil { 205 utils.Fatalf("Failed to read database stats: %v", err) 206 } 207 fmt.Println(stats) 208 fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses()) 209 fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads()) 210 211 // Print the memory statistics used by the importing 212 mem := new(runtime.MemStats) 213 runtime.ReadMemStats(mem) 214 215 fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(atomic.LoadUint64(&peakMemAlloc))/1024/1024) 216 fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(atomic.LoadUint64(&peakMemSys))/1024/1024) 217 fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000) 218 fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs)) 219 220 if ctx.GlobalIsSet(utils.NoCompactionFlag.Name) { 221 return nil 222 } 223 224 // Compact the entire database to more accurately measure disk io and print the stats 225 start = time.Now() 226 fmt.Println("Compacting entire database...") 227 if err = db.LDB().CompactRange(util.Range{}); err != nil { 228 utils.Fatalf("Compaction failed: %v", err) 229 } 230 fmt.Printf("Compaction done in %v.\n\n", time.Since(start)) 231 232 stats, err = db.LDB().GetProperty("leveldb.stats") 233 if err != nil { 234 utils.Fatalf("Failed to read database stats: %v", err) 235 } 236 fmt.Println(stats) 237 238 return nil 239 } 240 241 func exportChain(ctx *cli.Context) error { 242 if len(ctx.Args()) < 1 { 243 utils.Fatalf("This command requires an argument.") 244 } 245 stack := makeFullNode(ctx) 246 chain, _ := utils.MakeChain(ctx, stack) 247 start := time.Now() 248 249 var err error 250 fp := ctx.Args().First() 251 if len(ctx.Args()) < 3 { 252 err = utils.ExportChain(chain, fp) 253 } else { 254 // This can be improved to allow for numbers larger than 9223372036854775807 255 first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64) 256 last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64) 257 if ferr != nil || lerr != nil { 258 utils.Fatalf("Export error in parsing parameters: block number not an integer\n") 259 } 260 if first < 0 || last < 0 { 261 utils.Fatalf("Export error: block number must be greater than 0\n") 262 } 263 err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last)) 264 } 265 266 if err != nil { 267 utils.Fatalf("Export error: %v\n", err) 268 } 269 fmt.Printf("Export done in %v", time.Since(start)) 270 return nil 271 } 272 273 func removeDB(ctx *cli.Context) error { 274 stack, _ := makeConfigNode(ctx) 275 276 for _, name := range []string{"chaindata", "lightchaindata"} { 277 // Ensure the database exists in the first place 278 logger := log.New("database", name) 279 280 dbdir := stack.ResolvePath(name) 281 if !common.FileExist(dbdir) { 282 logger.Info("Database doesn't exist, skipping", "path", dbdir) 283 continue 284 } 285 // Confirm removal and execute 286 fmt.Println(dbdir) 287 confirm, err := console.Stdin.PromptConfirm("Remove this database?") 288 switch { 289 case err != nil: 290 utils.Fatalf("%v", err) 291 case !confirm: 292 logger.Warn("Database deletion aborted") 293 default: 294 start := time.Now() 295 os.RemoveAll(dbdir) 296 logger.Info("Database successfully deleted", "elapsed", common.PrettyDuration(time.Since(start))) 297 } 298 } 299 return nil 300 } 301 302 func dump(ctx *cli.Context) error { 303 stack := makeFullNode(ctx) 304 chain, chainDb := utils.MakeChain(ctx, stack) 305 for _, arg := range ctx.Args() { 306 var block *types.Block 307 if hashish(arg) { 308 block = chain.GetBlockByHash(common.HexToHash(arg)) 309 } else { 310 num, _ := strconv.Atoi(arg) 311 block = chain.GetBlockByNumber(uint64(num)) 312 } 313 if block == nil { 314 fmt.Println("{}") 315 utils.Fatalf("block not found") 316 } else { 317 state, err := state.New(block.Root(), chainDb) 318 if err != nil { 319 utils.Fatalf("could not create new state: %v", err) 320 } 321 fmt.Printf("%s\n", state.Dump()) 322 } 323 } 324 chainDb.Close() 325 return nil 326 } 327 328 // hashish returns true for strings that look like hashes. 329 func hashish(x string) bool { 330 _, err := strconv.Atoi(x) 331 return err != nil 332 }