github.com/phillinzzz/newBsc@v1.1.6/cmd/geth/dbcmd.go (about) 1 // Copyright 2020 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 "fmt" 21 "os" 22 "path/filepath" 23 "sort" 24 "strconv" 25 "time" 26 27 "github.com/phillinzzz/newBsc/cmd/utils" 28 "github.com/phillinzzz/newBsc/common" 29 "github.com/phillinzzz/newBsc/common/hexutil" 30 "github.com/phillinzzz/newBsc/console/prompt" 31 "github.com/phillinzzz/newBsc/core/rawdb" 32 "github.com/phillinzzz/newBsc/ethdb" 33 "github.com/phillinzzz/newBsc/log" 34 "github.com/phillinzzz/newBsc/trie" 35 "gopkg.in/urfave/cli.v1" 36 ) 37 38 var ( 39 removedbCommand = cli.Command{ 40 Action: utils.MigrateFlags(removeDB), 41 Name: "removedb", 42 Usage: "Remove blockchain and state databases", 43 ArgsUsage: "", 44 Flags: []cli.Flag{ 45 utils.DataDirFlag, 46 }, 47 Category: "DATABASE COMMANDS", 48 Description: ` 49 Remove blockchain and state databases`, 50 } 51 dbCommand = cli.Command{ 52 Name: "db", 53 Usage: "Low level database operations", 54 ArgsUsage: "", 55 Category: "DATABASE COMMANDS", 56 Subcommands: []cli.Command{ 57 dbInspectCmd, 58 dbStatCmd, 59 dbCompactCmd, 60 dbGetCmd, 61 dbDeleteCmd, 62 dbPutCmd, 63 dbGetSlotsCmd, 64 dbDumpFreezerIndex, 65 }, 66 } 67 dbInspectCmd = cli.Command{ 68 Action: utils.MigrateFlags(inspect), 69 Name: "inspect", 70 ArgsUsage: "<prefix> <start>", 71 Flags: []cli.Flag{ 72 utils.DataDirFlag, 73 utils.SyncModeFlag, 74 utils.MainnetFlag, 75 utils.RopstenFlag, 76 utils.RinkebyFlag, 77 utils.GoerliFlag, 78 utils.YoloV3Flag, 79 }, 80 Usage: "Inspect the storage size for each type of data in the database", 81 Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`, 82 } 83 dbStatCmd = cli.Command{ 84 Action: utils.MigrateFlags(dbStats), 85 Name: "stats", 86 Usage: "Print leveldb statistics", 87 Flags: []cli.Flag{ 88 utils.DataDirFlag, 89 utils.SyncModeFlag, 90 utils.MainnetFlag, 91 utils.RopstenFlag, 92 utils.RinkebyFlag, 93 utils.GoerliFlag, 94 utils.YoloV3Flag, 95 }, 96 } 97 dbCompactCmd = cli.Command{ 98 Action: utils.MigrateFlags(dbCompact), 99 Name: "compact", 100 Usage: "Compact leveldb database. WARNING: May take a very long time", 101 Flags: []cli.Flag{ 102 utils.DataDirFlag, 103 utils.SyncModeFlag, 104 utils.MainnetFlag, 105 utils.RopstenFlag, 106 utils.RinkebyFlag, 107 utils.GoerliFlag, 108 utils.YoloV3Flag, 109 utils.CacheFlag, 110 utils.CacheDatabaseFlag, 111 }, 112 Description: `This command performs a database compaction. 113 WARNING: This operation may take a very long time to finish, and may cause database 114 corruption if it is aborted during execution'!`, 115 } 116 dbGetCmd = cli.Command{ 117 Action: utils.MigrateFlags(dbGet), 118 Name: "get", 119 Usage: "Show the value of a database key", 120 ArgsUsage: "<hex-encoded key>", 121 Flags: []cli.Flag{ 122 utils.DataDirFlag, 123 utils.SyncModeFlag, 124 utils.MainnetFlag, 125 utils.RopstenFlag, 126 utils.RinkebyFlag, 127 utils.GoerliFlag, 128 utils.YoloV3Flag, 129 }, 130 Description: "This command looks up the specified database key from the database.", 131 } 132 dbDeleteCmd = cli.Command{ 133 Action: utils.MigrateFlags(dbDelete), 134 Name: "delete", 135 Usage: "Delete a database key (WARNING: may corrupt your database)", 136 ArgsUsage: "<hex-encoded key>", 137 Flags: []cli.Flag{ 138 utils.DataDirFlag, 139 utils.SyncModeFlag, 140 utils.MainnetFlag, 141 utils.RopstenFlag, 142 utils.RinkebyFlag, 143 utils.GoerliFlag, 144 utils.YoloV3Flag, 145 }, 146 Description: `This command deletes the specified database key from the database. 147 WARNING: This is a low-level operation which may cause database corruption!`, 148 } 149 dbPutCmd = cli.Command{ 150 Action: utils.MigrateFlags(dbPut), 151 Name: "put", 152 Usage: "Set the value of a database key (WARNING: may corrupt your database)", 153 ArgsUsage: "<hex-encoded key> <hex-encoded value>", 154 Flags: []cli.Flag{ 155 utils.DataDirFlag, 156 utils.SyncModeFlag, 157 utils.MainnetFlag, 158 utils.RopstenFlag, 159 utils.RinkebyFlag, 160 utils.GoerliFlag, 161 utils.YoloV3Flag, 162 }, 163 Description: `This command sets a given database key to the given value. 164 WARNING: This is a low-level operation which may cause database corruption!`, 165 } 166 dbGetSlotsCmd = cli.Command{ 167 Action: utils.MigrateFlags(dbDumpTrie), 168 Name: "dumptrie", 169 Usage: "Show the storage key/values of a given storage trie", 170 ArgsUsage: "<hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>", 171 Flags: []cli.Flag{ 172 utils.DataDirFlag, 173 utils.SyncModeFlag, 174 utils.MainnetFlag, 175 utils.RopstenFlag, 176 utils.RinkebyFlag, 177 utils.GoerliFlag, 178 utils.YoloV3Flag, 179 }, 180 Description: "This command looks up the specified database key from the database.", 181 } 182 dbDumpFreezerIndex = cli.Command{ 183 Action: utils.MigrateFlags(freezerInspect), 184 Name: "freezer-index", 185 Usage: "Dump out the index of a given freezer type", 186 ArgsUsage: "<type> <start (int)> <end (int)>", 187 Flags: []cli.Flag{ 188 utils.DataDirFlag, 189 utils.SyncModeFlag, 190 utils.MainnetFlag, 191 utils.RopstenFlag, 192 utils.RinkebyFlag, 193 utils.GoerliFlag, 194 utils.YoloV3Flag, 195 }, 196 Description: "This command displays information about the freezer index.", 197 } 198 ) 199 200 func removeDB(ctx *cli.Context) error { 201 stack, config := makeConfigNode(ctx) 202 203 // Remove the full node state database 204 path := stack.ResolvePath("chaindata") 205 if common.FileExist(path) { 206 confirmAndRemoveDB(path, "full node state database") 207 } else { 208 log.Info("Full node state database missing", "path", path) 209 } 210 // Remove the full node ancient database 211 path = config.Eth.DatabaseFreezer 212 switch { 213 case path == "": 214 path = filepath.Join(stack.ResolvePath("chaindata"), "ancient") 215 case !filepath.IsAbs(path): 216 path = config.Node.ResolvePath(path) 217 } 218 if common.FileExist(path) { 219 confirmAndRemoveDB(path, "full node ancient database") 220 } else { 221 log.Info("Full node ancient database missing", "path", path) 222 } 223 // Remove the light node database 224 path = stack.ResolvePath("lightchaindata") 225 if common.FileExist(path) { 226 confirmAndRemoveDB(path, "light node database") 227 } else { 228 log.Info("Light node database missing", "path", path) 229 } 230 return nil 231 } 232 233 // confirmAndRemoveDB prompts the user for a last confirmation and removes the 234 // folder if accepted. 235 func confirmAndRemoveDB(database string, kind string) { 236 confirm, err := prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove %s (%s)?", kind, database)) 237 switch { 238 case err != nil: 239 utils.Fatalf("%v", err) 240 case !confirm: 241 log.Info("Database deletion skipped", "path", database) 242 default: 243 start := time.Now() 244 filepath.Walk(database, func(path string, info os.FileInfo, err error) error { 245 // If we're at the top level folder, recurse into 246 if path == database { 247 return nil 248 } 249 // Delete all the files, but not subfolders 250 if !info.IsDir() { 251 os.Remove(path) 252 return nil 253 } 254 return filepath.SkipDir 255 }) 256 log.Info("Database successfully deleted", "path", database, "elapsed", common.PrettyDuration(time.Since(start))) 257 } 258 } 259 260 func inspect(ctx *cli.Context) error { 261 var ( 262 prefix []byte 263 start []byte 264 ) 265 if ctx.NArg() > 2 { 266 return fmt.Errorf("Max 2 arguments: %v", ctx.Command.ArgsUsage) 267 } 268 if ctx.NArg() >= 1 { 269 if d, err := hexutil.Decode(ctx.Args().Get(0)); err != nil { 270 return fmt.Errorf("failed to hex-decode 'prefix': %v", err) 271 } else { 272 prefix = d 273 } 274 } 275 if ctx.NArg() >= 2 { 276 if d, err := hexutil.Decode(ctx.Args().Get(1)); err != nil { 277 return fmt.Errorf("failed to hex-decode 'start': %v", err) 278 } else { 279 start = d 280 } 281 } 282 stack, _ := makeConfigNode(ctx) 283 defer stack.Close() 284 285 db := utils.MakeChainDatabase(ctx, stack, true) 286 defer db.Close() 287 288 return rawdb.InspectDatabase(db, prefix, start) 289 } 290 291 func showLeveldbStats(db ethdb.Stater) { 292 if stats, err := db.Stat("leveldb.stats"); err != nil { 293 log.Warn("Failed to read database stats", "error", err) 294 } else { 295 fmt.Println(stats) 296 } 297 if ioStats, err := db.Stat("leveldb.iostats"); err != nil { 298 log.Warn("Failed to read database iostats", "error", err) 299 } else { 300 fmt.Println(ioStats) 301 } 302 } 303 304 func dbStats(ctx *cli.Context) error { 305 stack, _ := makeConfigNode(ctx) 306 defer stack.Close() 307 308 db := utils.MakeChainDatabase(ctx, stack, true) 309 defer db.Close() 310 311 showLeveldbStats(db) 312 return nil 313 } 314 315 func dbCompact(ctx *cli.Context) error { 316 stack, _ := makeConfigNode(ctx) 317 defer stack.Close() 318 319 db := utils.MakeChainDatabase(ctx, stack, false) 320 defer db.Close() 321 322 log.Info("Stats before compaction") 323 showLeveldbStats(db) 324 325 log.Info("Triggering compaction") 326 if err := db.Compact(nil, nil); err != nil { 327 log.Info("Compact err", "error", err) 328 return err 329 } 330 log.Info("Stats after compaction") 331 showLeveldbStats(db) 332 return nil 333 } 334 335 // dbGet shows the value of a given database key 336 func dbGet(ctx *cli.Context) error { 337 if ctx.NArg() != 1 { 338 return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) 339 } 340 stack, _ := makeConfigNode(ctx) 341 defer stack.Close() 342 343 db := utils.MakeChainDatabase(ctx, stack, true) 344 defer db.Close() 345 346 key, err := hexutil.Decode(ctx.Args().Get(0)) 347 if err != nil { 348 log.Info("Could not decode the key", "error", err) 349 return err 350 } 351 data, err := db.Get(key) 352 if err != nil { 353 log.Info("Get operation failed", "error", err) 354 return err 355 } 356 fmt.Printf("key %#x: %#x\n", key, data) 357 return nil 358 } 359 360 // dbDelete deletes a key from the database 361 func dbDelete(ctx *cli.Context) error { 362 if ctx.NArg() != 1 { 363 return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) 364 } 365 stack, _ := makeConfigNode(ctx) 366 defer stack.Close() 367 368 db := utils.MakeChainDatabase(ctx, stack, false) 369 defer db.Close() 370 371 key, err := hexutil.Decode(ctx.Args().Get(0)) 372 if err != nil { 373 log.Info("Could not decode the key", "error", err) 374 return err 375 } 376 data, err := db.Get(key) 377 if err == nil { 378 fmt.Printf("Previous value: %#x\n", data) 379 } 380 if err = db.Delete(key); err != nil { 381 log.Info("Delete operation returned an error", "error", err) 382 return err 383 } 384 return nil 385 } 386 387 // dbPut overwrite a value in the database 388 func dbPut(ctx *cli.Context) error { 389 if ctx.NArg() != 2 { 390 return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) 391 } 392 stack, _ := makeConfigNode(ctx) 393 defer stack.Close() 394 395 db := utils.MakeChainDatabase(ctx, stack, false) 396 defer db.Close() 397 398 var ( 399 key []byte 400 value []byte 401 data []byte 402 err error 403 ) 404 key, err = hexutil.Decode(ctx.Args().Get(0)) 405 if err != nil { 406 log.Info("Could not decode the key", "error", err) 407 return err 408 } 409 value, err = hexutil.Decode(ctx.Args().Get(1)) 410 if err != nil { 411 log.Info("Could not decode the value", "error", err) 412 return err 413 } 414 data, err = db.Get(key) 415 if err == nil { 416 fmt.Printf("Previous value: %#x\n", data) 417 } 418 return db.Put(key, value) 419 } 420 421 // dbDumpTrie shows the key-value slots of a given storage trie 422 func dbDumpTrie(ctx *cli.Context) error { 423 if ctx.NArg() < 1 { 424 return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) 425 } 426 stack, _ := makeConfigNode(ctx) 427 defer stack.Close() 428 429 db := utils.MakeChainDatabase(ctx, stack, true) 430 defer db.Close() 431 var ( 432 root []byte 433 start []byte 434 max = int64(-1) 435 err error 436 ) 437 if root, err = hexutil.Decode(ctx.Args().Get(0)); err != nil { 438 log.Info("Could not decode the root", "error", err) 439 return err 440 } 441 stRoot := common.BytesToHash(root) 442 if ctx.NArg() >= 2 { 443 if start, err = hexutil.Decode(ctx.Args().Get(1)); err != nil { 444 log.Info("Could not decode the seek position", "error", err) 445 return err 446 } 447 } 448 if ctx.NArg() >= 3 { 449 if max, err = strconv.ParseInt(ctx.Args().Get(2), 10, 64); err != nil { 450 log.Info("Could not decode the max count", "error", err) 451 return err 452 } 453 } 454 theTrie, err := trie.New(stRoot, trie.NewDatabase(db)) 455 if err != nil { 456 return err 457 } 458 var count int64 459 it := trie.NewIterator(theTrie.NodeIterator(start)) 460 for it.Next() { 461 if max > 0 && count == max { 462 fmt.Printf("Exiting after %d values\n", count) 463 break 464 } 465 fmt.Printf(" %d. key %#x: %#x\n", count, it.Key, it.Value) 466 count++ 467 } 468 return it.Err 469 } 470 471 func freezerInspect(ctx *cli.Context) error { 472 var ( 473 start, end int64 474 disableSnappy bool 475 err error 476 ) 477 if ctx.NArg() < 3 { 478 return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) 479 } 480 kind := ctx.Args().Get(0) 481 if noSnap, ok := rawdb.FreezerNoSnappy[kind]; !ok { 482 var options []string 483 for opt := range rawdb.FreezerNoSnappy { 484 options = append(options, opt) 485 } 486 sort.Strings(options) 487 return fmt.Errorf("Could read freezer-type '%v'. Available options: %v", kind, options) 488 } else { 489 disableSnappy = noSnap 490 } 491 if start, err = strconv.ParseInt(ctx.Args().Get(1), 10, 64); err != nil { 492 log.Info("Could read start-param", "error", err) 493 return err 494 } 495 if end, err = strconv.ParseInt(ctx.Args().Get(2), 10, 64); err != nil { 496 log.Info("Could read count param", "error", err) 497 return err 498 } 499 stack, _ := makeConfigNode(ctx) 500 defer stack.Close() 501 path := filepath.Join(stack.ResolvePath("chaindata"), "ancient") 502 log.Info("Opening freezer", "location", path, "name", kind) 503 if f, err := rawdb.NewFreezerTable(path, kind, disableSnappy); err != nil { 504 return err 505 } else { 506 f.DumpIndex(start, end) 507 } 508 return nil 509 }