0280fa0264
This commit converts all block height references to int32 instead of int64. The current target block production rate is 10 mins per block which means it will take roughly 40,800 years to reach the maximum height an int32 affords. Even if the target rate were lowered to one block per minute, it would still take roughly another 4,080 years to reach the maximum. In the mean time, there is no reason to use a larger type which results in higher memory and disk space usage. However, for now, in order to avoid having to reserialize a bunch of database information, the heights are still serialized to the database as 8-byte uint64s. This is being mainly being done in preparation for further upcoming infrastructure changes which will use the smaller and more efficient 4-byte serialization in the database as well.
227 lines
5.4 KiB
Go
227 lines
5.4 KiB
Go
// Copyright (c) 2013 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
"github.com/btcsuite/btcd/database"
|
|
_ "github.com/btcsuite/btcd/database/ldb"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/btcsuite/btclog"
|
|
"github.com/btcsuite/btcutil"
|
|
flags "github.com/btcsuite/go-flags"
|
|
)
|
|
|
|
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"`
|
|
RegressionTest bool `long:"regtest" description:"Use the regression test network"`
|
|
SimNet bool `long:"simnet" description:"Use the simulation test network"`
|
|
ShaString string `short:"s" description:"Block SHA to process" required:"true"`
|
|
}
|
|
|
|
var (
|
|
btcdHomeDir = btcutil.AppDataDir("btcd", false)
|
|
defaultDataDir = filepath.Join(btcdHomeDir, "data")
|
|
log btclog.Logger
|
|
activeNetParams = &chaincfg.MainNetParams
|
|
)
|
|
|
|
const (
|
|
argSha = iota
|
|
argHeight
|
|
)
|
|
|
|
// netName returns the name used when referring to a bitcoin network. At the
|
|
// time of writing, btcd currently places blocks for testnet version 3 in the
|
|
// data and log directory "testnet", which does not match the Name field of the
|
|
// chaincfg parameters. This function can be used to override this directory name
|
|
// as "testnet" when the passed active network matches wire.TestNet3.
|
|
//
|
|
// A proper upgrade to move the data and log directories for this network to
|
|
// "testnet3" is planned for the future, at which point this function can be
|
|
// removed and the network parameter's name used instead.
|
|
func netName(chainParams *chaincfg.Params) string {
|
|
switch chainParams.Net {
|
|
case wire.TestNet3:
|
|
return "testnet"
|
|
default:
|
|
return chainParams.Name
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
cfg := config{
|
|
DbType: "leveldb",
|
|
DataDir: defaultDataDir,
|
|
}
|
|
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
|
|
}
|
|
|
|
backendLogger := btclog.NewDefaultBackendLogger()
|
|
defer backendLogger.Flush()
|
|
log = btclog.NewSubsystemLogger(backendLogger, "")
|
|
database.UseLogger(log)
|
|
|
|
// Multiple networks can't be selected simultaneously.
|
|
funcName := "main"
|
|
numNets := 0
|
|
// Count number of network flags passed; assign active network params
|
|
// while we're at it
|
|
if cfg.TestNet3 {
|
|
numNets++
|
|
activeNetParams = &chaincfg.TestNet3Params
|
|
}
|
|
if cfg.RegressionTest {
|
|
numNets++
|
|
activeNetParams = &chaincfg.RegressionNetParams
|
|
}
|
|
if cfg.SimNet {
|
|
numNets++
|
|
activeNetParams = &chaincfg.SimNetParams
|
|
}
|
|
if numNets > 1 {
|
|
str := "%s: The testnet, regtest, and simnet params can't be " +
|
|
"used together -- choose one of the three"
|
|
err := fmt.Errorf(str, funcName)
|
|
fmt.Fprintln(os.Stderr, err)
|
|
parser.WriteHelp(os.Stderr)
|
|
return
|
|
}
|
|
cfg.DataDir = filepath.Join(cfg.DataDir, netName(activeNetParams))
|
|
|
|
blockDbNamePrefix := "blocks"
|
|
dbName := blockDbNamePrefix + "_" + cfg.DbType
|
|
if cfg.DbType == "sqlite" {
|
|
dbName = dbName + ".db"
|
|
}
|
|
dbPath := filepath.Join(cfg.DataDir, dbName)
|
|
|
|
log.Infof("loading db")
|
|
db, err := database.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)
|
|
|
|
sha, err := getSha(db, cfg.ShaString)
|
|
if err != nil {
|
|
log.Infof("Invalid block hash %v", cfg.ShaString)
|
|
return
|
|
}
|
|
|
|
err = db.DropAfterBlockBySha(&sha)
|
|
if err != nil {
|
|
log.Warnf("failed %v", err)
|
|
}
|
|
|
|
}
|
|
|
|
func getSha(db database.Db, str string) (wire.ShaHash, error) {
|
|
argtype, idx, sha, err := parsesha(str)
|
|
if err != nil {
|
|
log.Warnf("unable to decode [%v] %v", str, err)
|
|
return wire.ShaHash{}, err
|
|
}
|
|
|
|
switch argtype {
|
|
case argSha:
|
|
// nothing to do
|
|
case argHeight:
|
|
sha, err = db.FetchBlockShaByHeight(idx)
|
|
if err != nil {
|
|
return wire.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 int32, psha *wire.ShaHash, err error) {
|
|
var sha wire.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 = int32(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
|
|
}
|