lbcd/util/dropafter/dropafter.go

206 lines
4.3 KiB
Go
Raw Normal View History

2013-10-04 17:11:38 +02:00
// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"errors"
"fmt"
"github.com/conformal/btcdb"
_ "github.com/conformal/btcdb/ldb"
"github.com/conformal/btcwire"
2013-10-10 19:58:11 +02:00
"github.com/conformal/go-flags"
"github.com/conformal/seelog"
"os"
"path/filepath"
"strconv"
)
type ShaHash btcwire.ShaHash
2013-10-10 19:58:11 +02:00
type config struct {
DataDir string `short:"b" long:"datadir" description:"Directory to store data"`
DbType string `long:"dbtype" description:"Database backend"`
TestNet3 bool `long:"testnet" description:"Use the test network"`
ShaString string `short:"s" description:"Block SHA to process" required:"true"`
}
var log seelog.LoggerInterface
const (
ArgSha = iota
ArgHeight
)
func main() {
2013-10-10 19:58:11 +02:00
cfg := config{
DbType: "leveldb",
DataDir: filepath.Join(btcdHomeDir(), "data"),
}
parser := flags.NewParser(&cfg, flags.Default)
_, err := parser.Parse()
if err != nil {
if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
parser.WriteHelp(os.Stderr)
}
return
}
log, err = seelog.LoggerFromWriterWithMinLevel(os.Stdout,
seelog.TraceLvl)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to create logger: %v", err)
return
}
defer log.Flush()
btcdb.UseLogger(log)
2013-10-10 19:58:11 +02:00
var testnet string
if cfg.TestNet3 {
testnet = "testnet"
} else {
testnet = "mainnet"
}
2013-10-10 19:58:11 +02:00
cfg.DataDir = filepath.Join(cfg.DataDir, testnet)
blockDbNamePrefix := "blocks"
2013-10-10 19:58:11 +02:00
dbName := blockDbNamePrefix + "_" + cfg.DbType
if cfg.DbType == "sqlite" {
dbName = dbName + ".db"
}
2013-10-10 19:58:11 +02:00
dbPath := filepath.Join(cfg.DataDir, dbName)
log.Infof("loading db")
2013-10-10 19:58:11 +02:00
db, err := btcdb.OpenDB(cfg.DbType, dbPath)
if err != nil {
log.Warnf("db open failed: %v", err)
return
}
defer db.Close()
log.Infof("db load complete")
_, height, err := db.NewestSha()
log.Infof("loaded block height %v", height)
2013-10-10 19:58:11 +02:00
sha, err := getSha(db, cfg.ShaString)
if err != nil {
2013-10-10 19:58:11 +02:00
log.Infof("Invalid block hash %v", cfg.ShaString)
return
}
err = db.DropAfterBlockBySha(&sha)
if err != nil {
log.Warnf("failed %v", err)
}
}
func getSha(db btcdb.Db, str string) (btcwire.ShaHash, error) {
argtype, idx, sha, err := parsesha(str)
if err != nil {
log.Warnf("unable to decode [%v] %v", str, err)
return btcwire.ShaHash{}, err
}
switch argtype {
case ArgSha:
// nothing to do
case ArgHeight:
sha, err = db.FetchBlockShaByHeight(idx)
if err != nil {
return btcwire.ShaHash{}, err
}
}
if sha == nil {
fmt.Printf("wtf sha is nil but err is %v", err)
}
return *sha, nil
}
var ntxcnt int64
var txspendcnt int64
var txgivecnt int64
var ErrBadShaPrefix = errors.New("invalid prefix")
var ErrBadShaLen = errors.New("invalid len")
var ErrBadShaChar = errors.New("invalid character")
func parsesha(argstr string) (argtype int, height int64, psha *btcwire.ShaHash, err error) {
var sha btcwire.ShaHash
var hashbuf string
switch len(argstr) {
case 64:
hashbuf = argstr
case 66:
if argstr[0:2] != "0x" {
log.Infof("prefix is %v", argstr[0:2])
err = ErrBadShaPrefix
return
}
hashbuf = argstr[2:]
default:
if len(argstr) <= 16 {
// assume value is height
argtype = ArgHeight
var h int
h, err = strconv.Atoi(argstr)
if err == nil {
height = int64(h)
return
}
log.Infof("Unable to parse height %v, err %v", height, err)
}
err = ErrBadShaLen
return
}
var buf [32]byte
for idx, ch := range hashbuf {
var val rune
switch {
case ch >= '0' && ch <= '9':
val = ch - '0'
case ch >= 'a' && ch <= 'f':
val = ch - 'a' + rune(10)
case ch >= 'A' && ch <= 'F':
val = ch - 'A' + rune(10)
default:
err = ErrBadShaChar
return
}
b := buf[31-idx/2]
if idx&1 == 1 {
b |= byte(val)
} else {
b |= (byte(val) << 4)
}
buf[31-idx/2] = b
}
sha.SetBytes(buf[0:32])
psha = &sha
return
}
// btcdHomeDir returns an OS appropriate home directory for btcd.
func btcdHomeDir() string {
2013-10-04 17:09:15 +02:00
// Search for Windows APPDATA first. This won't exist on POSIX OSes.
appData := os.Getenv("APPDATA")
if appData != "" {
return filepath.Join(appData, "btcd")
}
// Fall back to standard HOME directory that works for most POSIX OSes.
home := os.Getenv("HOME")
if home != "" {
return filepath.Join(home, ".btcd")
}
// In the worst case, use the current directory.
return "."
}