kaspad/cmd/findcheckpoint/findcheckpoint.go
stasatdaglabs ffd886498a [NOD-208] Make block reward maturity use the same mechanism as confirmations (#327)
* [NOD-208] Added blockBlueScore to UTXOEntry.

* [NOD-208] Added blueBlockScore to NewUTXOEntry.

* [NOD-208] Fixed compilation errors in policy, utxoset, and dag tests.

* [NOD-208] Changed validateBlockRewardMaturity and CheckTransactionInputsAndCalulateFee to use blueScore.

* [NOD-208] Changed CalcBlockSubsidy to use blueScore.

* [NOD-208] Changed SequenceLockActive to use blueScore.

* [NOD-208] Removed ExtractCoinbaseHeight.

* [NOD-208] Removed reference to block height in ensureNoDuplicateTx.

* [NOD-208] Changed IsFinalizedTransaction to use blueScore.

* [NOD-208] Fixed merge errors.

* [NOD-208] Made UTXOEntry serialization use blueScore.

* [NOD-208] Changed CalcPriority and calcInputValueAge to use blueScore.

* [NOD-208] Changed calcSequenceLock to use blueScore.

* [NOD-208] Removed blockChainHeight from UTXOEntry.

* [NOD-208] Fixed compilation errors in feeEstimator. Fixed a bug in the test pool hardness.

* [NOD-208] Fixed oldestChainBlockWithBlueScoreGreaterThan not handling an extreme case.

* [NOD-208] Fixed TestDiffFromTx.

* [NOD-208] Got rid of priority and support of free transactions.

* [NOD-208] Fixed TestProcessTransaction.

* [NOD-208] Fixed TestTxFeePrioHeap.

* [NOD-208] Fixed TestAddrIndex and TestFeeEstimatorCfg.

* [NOD-208] Removed unused rateLimit parameter from ProcessTransaction.

* [NOD-208] Fixed tests that rely on CreateTxChain.

* [NOD-208] Fixed tests that rely on CreateSignedTxForSubnetwork.

* [NOD-208] Fixed TestFetchTransaction.

* [NOD-208] Fixed TestHandleNewBlock. Fixed HandleNewBlock erroneously processing fee transactions.

* [NOD-208] Fixed TestTxIndexConnectBlock.

* [NOD-208] Removed the use of Height() from the fee estimator.

* [NOD-208] Removed unused methods from rpcwebsocket.go.

* [NOD-208] Removed Height from util.Block.

* [NOD-208] Removed ErrForkTooOld. It doesn't make sense in a DAG.

* [NOD-208] Made blockHeap use blueScore instead of height.

* [NOD-208] Removed fee estimator.

* [NOD-208] Removed DAG.Height.

* [NOD-208] Made TestAncestorErrors test chainHeight instead of height.

* [NOD-208] Fixed a couple of comments that were still speaking about block height.

* [NOD-208] Replaced all uses of HighestTipHash with SelectedTipHash.

* [NOD-208] Remove blockNode highest and some remaining erroneous uses of height.

* [NOD-208] Fixed a couple of comments. Fixed outPoint -> outpoint merge error.

* [NOD-208] Fixed a couple more comments.

* [NOD-208] Used calcMinRequiredTxRelayFee instead of DefaultMinRelayTxFee for mempool tests.

* [NOD-208] Renamed mempool Config BestHeight to DAGChainHeight.

* [NOD-208] Fixed a bug in oldestChainBlockWithBlueScoreGreaterThan. Made calcSequenceLock use the node's selected parent chain rather than the virtual block's.

* [NOD-208] Removed chainHeight from blockNode String().
Renamed checkpointsByHeight to checkpointsByChainHeight and prevCheckpointHeight to prevCheckpointChainHeight.
Removed reference to chainHeight in blockIndexKey.
Fixed comments in dagio.go.

* [NOD-208] Removed indexers/blocklogger.go, as no one was using it.

* [NOD-208] Made blocklogger.go log blueScore instead of height.

* [NOD-208] Fixed typo.

* [NOD-208] Fixed comments, did minor renaming.

* [NOD-208] Made a "common sense" wrapper around sort.Search.

* [NOD-208] Fixed comment in SearchSlice.
2019-06-16 14:12:02 +03:00

186 lines
5.4 KiB
Go

// Copyright (c) 2013-2016 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 (
"fmt"
"os"
"path/filepath"
"github.com/daglabs/btcd/blockdag"
"github.com/daglabs/btcd/dagconfig"
"github.com/daglabs/btcd/database"
"github.com/daglabs/btcd/util/daghash"
)
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 DAG 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 since there
// is no point in finding candidates before already existing checkpoints.
func findCandidates(dag *blockdag.BlockDAG, highestTipHash *daghash.Hash) ([]*dagconfig.Checkpoint, error) {
// Start with the selected tip.
block, err := dag.BlockByHash(highestTipHash)
if err != nil {
return nil, err
}
// Get the latest known checkpoint.
latestCheckpoint := dag.LatestCheckpoint()
if latestCheckpoint == nil {
// Set the latest checkpoint to the genesis block if there isn't
// already one.
latestCheckpoint = &dagconfig.Checkpoint{
Hash: activeNetParams.GenesisHash,
ChainHeight: 0,
}
}
// The latest known block must be at least the last known checkpoint
// plus required checkpoint confirmations.
checkpointConfirmations := uint64(blockdag.CheckpointConfirmations)
requiredChainHeight := latestCheckpoint.ChainHeight + checkpointConfirmations
if block.ChainHeight() < requiredChainHeight {
return nil, fmt.Errorf("the block database is only at chain "+
"height %d which is less than the latest checkpoint chain height "+
"of %d plus required confirmations of %d",
block.ChainHeight(), latestCheckpoint.ChainHeight,
checkpointConfirmations)
}
// For the first checkpoint, the required height is any block after the
// genesis block, so long as the DAG has at least the required number
// of confirmations (which is enforced above).
if len(activeNetParams.Checkpoints) == 0 {
requiredChainHeight = 1
}
// Indeterminate progress setup.
numBlocksToTest := block.ChainHeight() - requiredChainHeight
progressInterval := (numBlocksToTest / 100) + 1 // min 1
fmt.Print("Searching for candidates")
defer fmt.Println()
// Loop backwards through the DAG to find checkpoint candidates.
candidates := make([]*dagconfig.Checkpoint, 0, cfg.NumCandidates)
numTested := uint64(0)
for len(candidates) < cfg.NumCandidates && block.ChainHeight() > requiredChainHeight {
// Display progress.
if numTested%progressInterval == 0 {
fmt.Print(".")
}
// Determine if this block is a checkpoint candidate.
isCandidate, err := dag.IsCheckpointCandidate(block)
if err != nil {
return nil, err
}
// All checks passed, so this node seems like a reasonable
// checkpoint candidate.
if isCandidate {
checkpoint := dagconfig.Checkpoint{
ChainHeight: block.ChainHeight(),
Hash: block.Hash(),
}
candidates = append(candidates, &checkpoint)
}
parentHashes := block.MsgBlock().Header.ParentHashes
selectedBlockHash := parentHashes[0]
block, err = dag.BlockByHash(selectedBlockHash)
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 btcchain code expects for checkpoints added to the list.
func showCandidate(candidateNum int, checkpoint *dagconfig.Checkpoint) {
if cfg.UseGoOutput {
fmt.Printf("Candidate %d -- {%d, newShaHashFromStr(\"%s\")},\n",
candidateNum, checkpoint.ChainHeight, checkpoint.Hash)
return
}
fmt.Printf("Candidate %d -- ChainHeight: %d, Hash: %s\n", candidateNum,
checkpoint.ChainHeight, 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()
// Setup chain. Ignore notifications since they aren't needed for this
// util.
dag, err := blockdag.New(&blockdag.Config{
DB: db,
DAGParams: activeNetParams,
TimeSource: blockdag.NewMedianTime(),
})
if err != nil {
fmt.Fprintf(os.Stderr, "failed to initialize chain: %s\n", err)
return
}
// Get the latest block hash and height from the database and report
// status.
fmt.Printf("Block database loaded with block chain height %d\n", dag.ChainHeight())
// Find checkpoint candidates.
selectedTipHash := dag.SelectedTipHash()
candidates, err := findCandidates(dag, selectedTipHash)
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)
}
}