github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/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 "bufio" 21 "fmt" 22 "log" 23 "os" 24 "path/filepath" 25 "strconv" 26 "strings" 27 "time" 28 29 "github.com/ethereumproject/go-ethereum/common" 30 "github.com/ethereumproject/go-ethereum/core" 31 "github.com/ethereumproject/go-ethereum/core/state" 32 "github.com/ethereumproject/go-ethereum/core/types" 33 "github.com/ethereumproject/go-ethereum/logger/glog" 34 "gopkg.in/urfave/cli.v1" 35 ) 36 37 var ( 38 importCommand = cli.Command{ 39 Action: importChain, 40 Name: "import", 41 Usage: `Import a blockchain file`, 42 } 43 exportCommand = cli.Command{ 44 Action: exportChain, 45 Name: "export", 46 Usage: `Export blockchain into file`, 47 Description: ` 48 Requires a first argument of the file to write to. 49 Optional second and third arguments control the first and 50 last block to write. In this mode, the file will be appended 51 if already existing. 52 `, 53 } 54 upgradedbCommand = cli.Command{ 55 Action: upgradeDB, 56 Name: "upgrade-db", 57 Aliases: []string{"upgradedb"}, 58 Usage: "Upgrade chainblock database", 59 } 60 dumpCommand = cli.Command{ 61 Action: dump, 62 Name: "dump", 63 Usage: `Dump a specific block from storage`, 64 Description: ` 65 The arguments are interpreted as block numbers or hashes. 66 Use "$ geth dump 0" to dump the genesis block. 67 `, 68 } 69 dumpChainConfigCommand = cli.Command{ 70 Action: dumpChainConfig, 71 Name: "dump-chain-config", 72 Aliases: []string{"dumpchainconfig"}, 73 Usage: "Dump current chain configuration to JSON file [REQUIRED argument: filepath.json]", 74 Description: ` 75 The dump external configuration command writes a JSON file containing pertinent configuration data for 76 the configuration of a chain database. It includes genesis block data as well as chain fork settings. 77 `, 78 } 79 rollbackCommand = cli.Command{ 80 Action: rollback, 81 Name: "rollback", 82 Aliases: []string{"roll-back", "set-head", "sethead"}, 83 Usage: "Set current head for blockchain, purging antecedent blocks", 84 Description: ` 85 Rollback set the current head block for block chain already in the database. 86 This is a destructive action, purging any block more recent than the index specified. 87 Syncing will require downloading contemporary block information from the index onwards. 88 `, 89 } 90 statusCommand = cli.Command{ 91 Action: status, 92 Name: "status", 93 Usage: "Display the status of the current node", 94 Description: ` 95 Show the status of the current configuration. 96 `, 97 } 98 resetCommand = cli.Command{ 99 Action: resetChaindata, 100 Name: "reset", 101 Usage: "Reset (remove) the chain database", 102 Description: ` 103 Reset does a hard reset of the entire chain database. 104 This is a drastic and irreversible command, and should be used with caution. 105 The command will require user confirmation before any action is taken. 106 `, 107 } 108 recoverCommand = cli.Command{ 109 Action: recoverChaindata, 110 Name: "recover", 111 Usage: "Attempt blockchain data recovery in case of data corruption", 112 Description: ` 113 Recover scans and health-checks all available blockchain data in order 114 to recover all consistent and healthy block data. It will remove invalid or 115 corrupt block data that may have been caused by hard killing, system failure, 116 space limitations, or attack. 117 `, 118 } 119 ) 120 121 func importChain(ctx *cli.Context) error { 122 if len(ctx.Args()) != 1 { 123 log.Fatal("This command requires an argument.") 124 } 125 chain, chainDb := MakeChain(ctx) 126 start := time.Now() 127 err := ImportChain(chain, ctx.Args().First()) 128 chainDb.Close() 129 if err != nil { 130 log.Fatal("Import error: ", err) 131 } 132 fmt.Printf("Import done in %v", time.Since(start)) 133 return nil 134 } 135 136 func exportChain(ctx *cli.Context) error { 137 if len(ctx.Args()) < 1 { 138 log.Fatal("This command requires an argument.") 139 } 140 chain, _ := MakeChain(ctx) 141 start := time.Now() 142 143 fp := ctx.Args().First() 144 if len(ctx.Args()) < 3 { 145 if err := ExportChain(chain, fp); err != nil { 146 log.Fatal(err) 147 } 148 } else { 149 // This can be improved to allow for numbers larger than 9223372036854775807 150 first, err := strconv.ParseUint(ctx.Args().Get(1), 10, 64) 151 if err != nil { 152 log.Fatal("export paramater: ", err) 153 } 154 last, err := strconv.ParseUint(ctx.Args().Get(2), 10, 64) 155 if err != nil { 156 log.Fatal("export paramater: ", err) 157 } 158 if err = ExportAppendChain(chain, fp, first, last); err != nil { 159 log.Fatal(err) 160 } 161 } 162 163 fmt.Printf("Export done in %v", time.Since(start)) 164 return nil 165 } 166 167 func upgradeDB(ctx *cli.Context) error { 168 glog.Infoln("Upgrading blockchain database") 169 170 chain, chainDb := MakeChain(ctx) 171 bcVersion := core.GetBlockChainVersion(chainDb) 172 if bcVersion == 0 { 173 bcVersion = core.BlockChainVersion 174 } 175 176 // Export the current chain. 177 filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405")) 178 exportFile := filepath.Join(ctx.GlobalString(DataDirFlag.Name), filename) 179 if err := ExportChain(chain, exportFile); err != nil { 180 log.Fatal("Unable to export chain for reimport ", err) 181 } 182 chainDb.Close() 183 os.RemoveAll(filepath.Join(ctx.GlobalString(DataDirFlag.Name), "chaindata")) 184 185 // Import the chain file. 186 chain, chainDb = MakeChain(ctx) 187 core.WriteBlockChainVersion(chainDb, core.BlockChainVersion) 188 err := ImportChain(chain, exportFile) 189 chainDb.Close() 190 if err != nil { 191 log.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile) 192 } else { 193 os.Remove(exportFile) 194 glog.Infoln("Import finished") 195 } 196 return nil 197 } 198 199 // Original use allows n hashes|ints as space-separated arguments, dumping entire state for each block n[x]. 200 // $ geth dump [hash|num] [hash|num] ... [hash|num] 201 // $ geth dump 0x234234234234233 42 43 0xlksdf234r23r234223 202 // 203 // Revised use allows n hashes|ints as comma-separated first argument and n addresses as comma-separated second argument, 204 // dumping only state information for given addresses if they're present. 205 // revised use: $ geth dump [hash|num],[hash|num],...,[hash|num] [address],[address],...,[address] 206 // 207 // Added unsorted/sorted dumping algorithms. 208 // unsorted dump is used by default. 209 // revised use: $ geth dump [sorted] [hash|num],[hash|num],...,[hash|num] [address],[address],...,[address] 210 211 func dump(ctx *cli.Context) error { 212 213 if ctx.NArg() == 0 { 214 return fmt.Errorf("%v: use: $ geth dump [blockHash|blockNum],[blockHash|blockNum] [[addressHex|addressPrefixedHex],[addressHex|addressPrefixedHex]]", ErrInvalidFlag) 215 } 216 217 firstArg := 0 218 sorted := ctx.Args()[0] == "sorted" 219 if sorted { 220 firstArg = 1 221 } 222 223 blocks := strings.Split(ctx.Args()[firstArg], ",") 224 addresses := []common.Address{} 225 argaddress := "" 226 if ctx.NArg() > firstArg+1 { 227 argaddress = ctx.Args()[firstArg+1] 228 } 229 230 if argaddress != "" { 231 argaddresses := strings.Split(argaddress, ",") 232 for _, a := range argaddresses { 233 addresses = append(addresses, common.HexToAddress(strings.TrimSpace(a))) 234 } 235 } 236 237 chain, chainDb := MakeChain(ctx) 238 defer chainDb.Close() 239 240 prefix := "" 241 indent := " " 242 243 out := bufio.NewWriter(os.Stdout) 244 245 if len(blocks) > 1 { 246 prefix = indent 247 out.WriteString("[\n") 248 } 249 250 for n, b := range blocks { 251 b = strings.TrimSpace(b) 252 var block *types.Block 253 if hashish(b) { 254 block = chain.GetBlock(common.HexToHash(b)) 255 } else { 256 num, _ := strconv.Atoi(b) 257 block = chain.GetBlockByNumber(uint64(num)) 258 } 259 if block == nil { 260 out.WriteString("{}\n") 261 log.Fatal("block not found") 262 } else { 263 state, err := state.New(block.Root(), state.NewDatabase(chainDb)) 264 if err != nil { 265 return fmt.Errorf("could not create new state: %v", err) 266 } 267 268 if n != 0 { 269 out.WriteString(",\n") 270 } 271 272 if sorted { 273 err = state.SortedDump(addresses, prefix, indent, out) 274 } else { 275 err = state.UnsortedDump(addresses, prefix, indent, out) 276 } 277 278 if err != nil { 279 return err 280 } 281 } 282 } 283 284 if len(blocks) > 1 { 285 out.WriteString("\n]") 286 } 287 288 out.WriteString("\n") 289 out.Flush() 290 291 return nil 292 } 293 294 // hashish returns true for strings that look like hashes. 295 func hashish(x string) bool { 296 _, err := strconv.Atoi(x) 297 return err != nil 298 }