findcheckpoints: Remove utility.
This utility is no longer be necessary since the manual checkpoint logic is being reworked in upcoming commits.
This commit is contained in:
parent
f31191a8c8
commit
d4a0310073
@ -1,129 +0,0 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2015-2020 The Decred 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"
|
||||
|
||||
"github.com/decred/dcrd/chaincfg/v3"
|
||||
"github.com/decred/dcrd/database/v3"
|
||||
_ "github.com/decred/dcrd/database/v3/ffldb"
|
||||
"github.com/decred/dcrd/dcrutil/v4"
|
||||
flags "github.com/jessevdk/go-flags"
|
||||
)
|
||||
|
||||
const (
|
||||
minCandidates = 1
|
||||
maxCandidates = 20
|
||||
defaultNumCandidates = 5
|
||||
defaultDbType = "ffldb"
|
||||
)
|
||||
|
||||
var (
|
||||
dcrdHomeDir = dcrutil.AppDataDir("dcrd", false)
|
||||
defaultDataDir = filepath.Join(dcrdHomeDir, "data")
|
||||
knownDbTypes = database.SupportedDrivers()
|
||||
activeNetParams = chaincfg.MainNetParams()
|
||||
)
|
||||
|
||||
// config defines the configuration options for findcheckpoint.
|
||||
//
|
||||
// See loadConfig for details on the configuration load process.
|
||||
type config struct {
|
||||
DataDir string `short:"b" long:"datadir" description:"Location of the dcrd data directory"`
|
||||
DbType string `long:"dbtype" description:"Database backend to use for the Block Chain"`
|
||||
TestNet bool `long:"testnet" description:"Use the test network"`
|
||||
SimNet bool `long:"simnet" description:"Use the simulation test network"`
|
||||
NumCandidates int `short:"n" long:"numcandidates" description:"Max num of checkpoint candidates to show {1-20}"`
|
||||
UseGoOutput bool `short:"g" long:"gooutput" description:"Display the candidates using Go syntax that is ready to insert into the dcrchain checkpoint list"`
|
||||
}
|
||||
|
||||
// validDbType returns whether or not dbType is a supported database type.
|
||||
func validDbType(dbType string) bool {
|
||||
for _, knownType := range knownDbTypes {
|
||||
if dbType == knownType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// loadConfig initializes and parses the config using command line options.
|
||||
func loadConfig() (*config, []string, error) {
|
||||
// Default config.
|
||||
cfg := config{
|
||||
DataDir: defaultDataDir,
|
||||
DbType: defaultDbType,
|
||||
NumCandidates: defaultNumCandidates,
|
||||
}
|
||||
|
||||
// Parse command line options.
|
||||
parser := flags.NewParser(&cfg, flags.Default)
|
||||
remainingArgs, err := parser.Parse()
|
||||
if err != nil {
|
||||
var e *flags.Error
|
||||
if !errors.As(err, &e) || e.Type != flags.ErrHelp {
|
||||
parser.WriteHelp(os.Stderr)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Multiple networks can't be selected simultaneously.
|
||||
funcName := "loadConfig"
|
||||
numNets := 0
|
||||
// Count number of network flags passed; assign active network params
|
||||
// while we're at it
|
||||
if cfg.TestNet {
|
||||
numNets++
|
||||
activeNetParams = chaincfg.TestNet3Params()
|
||||
}
|
||||
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 nil, nil, err
|
||||
}
|
||||
|
||||
// Validate database type.
|
||||
if !validDbType(cfg.DbType) {
|
||||
str := "%s: the specified database type [%v] is invalid -- " +
|
||||
"supported types %v"
|
||||
err := fmt.Errorf(str, "loadConfig", cfg.DbType, knownDbTypes)
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
parser.WriteHelp(os.Stderr)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Append the network type to the data directory so it is "namespaced"
|
||||
// per network. In addition to the block database, there are other
|
||||
// pieces of data that are saved to disk such as address manager state.
|
||||
// All data is specific to a network, so namespacing the data directory
|
||||
// means each individual piece of serialized data does not have to
|
||||
// worry about changing names per network and such.
|
||||
cfg.DataDir = filepath.Join(cfg.DataDir, activeNetParams.Name)
|
||||
|
||||
// Validate the number of candidates.
|
||||
if cfg.NumCandidates < minCandidates || cfg.NumCandidates > maxCandidates {
|
||||
str := "%s: The specified number of candidates is out of " +
|
||||
"range -- parsed [%v]"
|
||||
err = fmt.Errorf(str, "loadConfig", cfg.NumCandidates)
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
parser.WriteHelp(os.Stderr)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &cfg, remainingArgs, nil
|
||||
}
|
||||
@ -1,205 +0,0 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2015-2022 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/decred/dcrd/blockchain/v5"
|
||||
"github.com/decred/dcrd/chaincfg/chainhash"
|
||||
"github.com/decred/dcrd/chaincfg/v3"
|
||||
"github.com/decred/dcrd/database/v3"
|
||||
)
|
||||
|
||||
const blockDbNamePrefix = "blocks"
|
||||
|
||||
var (
|
||||
cfg *config
|
||||
)
|
||||
|
||||
// loadBlockDB opens the block database and returns a handle to it.
|
||||
func loadBlockDB() (database.DB, error) {
|
||||
// The database name is based on the database type.
|
||||
dbName := blockDbNamePrefix + "_" + cfg.DbType
|
||||
dbPath := filepath.Join(cfg.DataDir, dbName)
|
||||
fmt.Printf("Loading block database from '%s'\n", dbPath)
|
||||
db, err := database.Open(cfg.DbType, dbPath, activeNetParams.Net)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// findCandidates searches the chain backwards for checkpoint candidates and
|
||||
// returns a slice of found candidates, if any. It also stops searching for
|
||||
// candidates at the last checkpoint that is already hard coded into chain
|
||||
// since there is no point in finding candidates before already existing
|
||||
// checkpoints.
|
||||
func findCandidates(chain *blockchain.BlockChain, latestHash *chainhash.Hash) ([]*chaincfg.Checkpoint, error) {
|
||||
// Start with the latest block of the main chain.
|
||||
block, err := chain.BlockByHash(latestHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the latest known checkpoint.
|
||||
latestCheckpoint := chain.LatestCheckpoint()
|
||||
if latestCheckpoint == nil {
|
||||
// Set the latest checkpoint to the genesis block if there isn't
|
||||
// already one.
|
||||
latestCheckpoint = &chaincfg.Checkpoint{
|
||||
Hash: &activeNetParams.GenesisHash,
|
||||
Height: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// The latest known block must be at least the last known checkpoint
|
||||
// plus required checkpoint confirmations.
|
||||
checkpointConfirmations := int64(blockchain.CheckpointConfirmations)
|
||||
requiredHeight := latestCheckpoint.Height + checkpointConfirmations
|
||||
if block.Height() < requiredHeight {
|
||||
return nil, fmt.Errorf("the block database is only at height "+
|
||||
"%d which is less than the latest checkpoint height "+
|
||||
"of %d plus required confirmations of %d",
|
||||
block.Height(), latestCheckpoint.Height,
|
||||
checkpointConfirmations)
|
||||
}
|
||||
|
||||
// For the first checkpoint, the required height is any block after the
|
||||
// genesis block, so long as the chain has at least the required number
|
||||
// of confirmations (which is enforced above).
|
||||
if len(activeNetParams.Checkpoints) == 0 {
|
||||
requiredHeight = 1
|
||||
}
|
||||
|
||||
// Indeterminate progress setup.
|
||||
numBlocksToTest := block.Height() - requiredHeight
|
||||
progressInterval := (numBlocksToTest / 100) + 1 // min 1
|
||||
fmt.Print("Searching for candidates")
|
||||
defer fmt.Println()
|
||||
|
||||
// Loop backwards through the chain to find checkpoint candidates.
|
||||
candidates := make([]*chaincfg.Checkpoint, 0, cfg.NumCandidates)
|
||||
numTested := int64(0)
|
||||
for len(candidates) < cfg.NumCandidates && block.Height() > requiredHeight {
|
||||
// Display progress.
|
||||
if numTested%progressInterval == 0 {
|
||||
fmt.Print(".")
|
||||
}
|
||||
|
||||
// Determine if this block is a checkpoint candidate.
|
||||
isCandidate, err := chain.IsCheckpointCandidate(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// All checks passed, so this node seems like a reasonable
|
||||
// checkpoint candidate.
|
||||
if isCandidate {
|
||||
checkpoint := chaincfg.Checkpoint{
|
||||
Height: block.Height(),
|
||||
Hash: block.Hash(),
|
||||
}
|
||||
candidates = append(candidates, &checkpoint)
|
||||
}
|
||||
|
||||
prevHash := &block.MsgBlock().Header.PrevBlock
|
||||
block, err = chain.BlockByHash(prevHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
numTested++
|
||||
}
|
||||
return candidates, nil
|
||||
}
|
||||
|
||||
// showCandidate display a checkpoint candidate using and output format
|
||||
// determined by the configuration parameters. The Go syntax output
|
||||
// uses the format the chain code expects for checkpoints added to the list.
|
||||
func showCandidate(candidateNum int, checkpoint *chaincfg.Checkpoint) {
|
||||
if cfg.UseGoOutput {
|
||||
fmt.Printf("Candidate %d -- {%d, newHashFromStr(\"%v\")},\n",
|
||||
candidateNum, checkpoint.Height, checkpoint.Hash)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Candidate %d -- Height: %d, Hash: %v\n", candidateNum,
|
||||
checkpoint.Height, checkpoint.Hash)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Load configuration and parse command line.
|
||||
tcfg, _, err := loadConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cfg = tcfg
|
||||
|
||||
// Load the block database.
|
||||
db, err := loadBlockDB()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "failed to load database:", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
// Load the UTXO database.
|
||||
utxoDb, err := blockchain.LoadUtxoDB(context.Background(), activeNetParams,
|
||||
cfg.DataDir)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "failed to load UTXO database:", err)
|
||||
return
|
||||
}
|
||||
defer utxoDb.Close()
|
||||
|
||||
// Instantiate a UTXO backend and UTXO cache.
|
||||
utxoBackend := blockchain.NewLevelDbUtxoBackend(utxoDb)
|
||||
utxoCache := blockchain.NewUtxoCache(&blockchain.UtxoCacheConfig{
|
||||
Backend: utxoBackend,
|
||||
FlushBlockDB: db.Flush,
|
||||
MaxSize: 100 * 1024 * 1024, // 100 MiB
|
||||
})
|
||||
|
||||
// Setup chain. Ignore notifications since they aren't needed for this
|
||||
// util.
|
||||
chain, err := blockchain.New(context.Background(),
|
||||
&blockchain.Config{
|
||||
DB: db,
|
||||
ChainParams: activeNetParams,
|
||||
UtxoBackend: blockchain.NewLevelDbUtxoBackend(utxoDb),
|
||||
UtxoCache: utxoCache,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to initialize chain: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Get the latest block hash and height from the database and report
|
||||
// status.
|
||||
best := chain.BestSnapshot()
|
||||
fmt.Printf("Block database loaded with block height %d\n", best.Height)
|
||||
|
||||
// Find checkpoint candidates.
|
||||
candidates, err := findCandidates(chain, &best.Hash)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Unable to identify candidates:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// No candidates.
|
||||
if len(candidates) == 0 {
|
||||
fmt.Println("No candidates found.")
|
||||
return
|
||||
}
|
||||
|
||||
// Show the candidates.
|
||||
for i, checkpoint := range candidates {
|
||||
showCandidate(i+1, checkpoint)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user