OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / cmd / findcheckpoint / findcheckpoint.go
1 // Copyright (c) 2013-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
4
5 package main
6
7 import (
8         "fmt"
9         "os"
10         "path/filepath"
11
12         "github.com/btcsuite/btcd/blockchain"
13         "github.com/btcsuite/btcd/chaincfg"
14         "github.com/btcsuite/btcd/chaincfg/chainhash"
15         "github.com/btcsuite/btcd/database"
16 )
17
18 const blockDbNamePrefix = "blocks"
19
20 var (
21         cfg *config
22 )
23
24 // loadBlockDB opens the block database and returns a handle to it.
25 func loadBlockDB() (database.DB, error) {
26         // The database name is based on the database type.
27         dbName := blockDbNamePrefix + "_" + cfg.DbType
28         dbPath := filepath.Join(cfg.DataDir, dbName)
29         fmt.Printf("Loading block database from '%s'\n", dbPath)
30         db, err := database.Open(cfg.DbType, dbPath, activeNetParams.Net)
31         if err != nil {
32                 return nil, err
33         }
34         return db, nil
35 }
36
37 // findCandidates searches the chain backwards for checkpoint candidates and
38 // returns a slice of found candidates, if any.  It also stops searching for
39 // candidates at the last checkpoint that is already hard coded into btcchain
40 // since there is no point in finding candidates before already existing
41 // checkpoints.
42 func findCandidates(chain *blockchain.BlockChain, latestHash *chainhash.Hash) ([]*chaincfg.Checkpoint, error) {
43         // Start with the latest block of the main chain.
44         block, err := chain.BlockByHash(latestHash)
45         if err != nil {
46                 return nil, err
47         }
48
49         // Get the latest known checkpoint.
50         latestCheckpoint := chain.LatestCheckpoint()
51         if latestCheckpoint == nil {
52                 // Set the latest checkpoint to the genesis block if there isn't
53                 // already one.
54                 latestCheckpoint = &chaincfg.Checkpoint{
55                         Hash:   activeNetParams.GenesisHash,
56                         Height: 0,
57                 }
58         }
59
60         // The latest known block must be at least the last known checkpoint
61         // plus required checkpoint confirmations.
62         checkpointConfirmations := int32(blockchain.CheckpointConfirmations)
63         requiredHeight := latestCheckpoint.Height + checkpointConfirmations
64         if block.Height() < requiredHeight {
65                 return nil, fmt.Errorf("the block database is only at height "+
66                         "%d which is less than the latest checkpoint height "+
67                         "of %d plus required confirmations of %d",
68                         block.Height(), latestCheckpoint.Height,
69                         checkpointConfirmations)
70         }
71
72         // For the first checkpoint, the required height is any block after the
73         // genesis block, so long as the chain has at least the required number
74         // of confirmations (which is enforced above).
75         if len(activeNetParams.Checkpoints) == 0 {
76                 requiredHeight = 1
77         }
78
79         // Indeterminate progress setup.
80         numBlocksToTest := block.Height() - requiredHeight
81         progressInterval := (numBlocksToTest / 100) + 1 // min 1
82         fmt.Print("Searching for candidates")
83         defer fmt.Println()
84
85         // Loop backwards through the chain to find checkpoint candidates.
86         candidates := make([]*chaincfg.Checkpoint, 0, cfg.NumCandidates)
87         numTested := int32(0)
88         for len(candidates) < cfg.NumCandidates && block.Height() > requiredHeight {
89                 // Display progress.
90                 if numTested%progressInterval == 0 {
91                         fmt.Print(".")
92                 }
93
94                 // Determine if this block is a checkpoint candidate.
95                 isCandidate, err := chain.IsCheckpointCandidate(block)
96                 if err != nil {
97                         return nil, err
98                 }
99
100                 // All checks passed, so this node seems like a reasonable
101                 // checkpoint candidate.
102                 if isCandidate {
103                         checkpoint := chaincfg.Checkpoint{
104                                 Height: block.Height(),
105                                 Hash:   block.Hash(),
106                         }
107                         candidates = append(candidates, &checkpoint)
108                 }
109
110                 prevHash := &block.MsgBlock().Header.PrevBlock
111                 block, err = chain.BlockByHash(prevHash)
112                 if err != nil {
113                         return nil, err
114                 }
115                 numTested++
116         }
117         return candidates, nil
118 }
119
120 // showCandidate display a checkpoint candidate using and output format
121 // determined by the configuration parameters.  The Go syntax output
122 // uses the format the btcchain code expects for checkpoints added to the list.
123 func showCandidate(candidateNum int, checkpoint *chaincfg.Checkpoint) {
124         if cfg.UseGoOutput {
125                 fmt.Printf("Candidate %d -- {%d, newShaHashFromStr(\"%v\")},\n",
126                         candidateNum, checkpoint.Height, checkpoint.Hash)
127                 return
128         }
129
130         fmt.Printf("Candidate %d -- Height: %d, Hash: %v\n", candidateNum,
131                 checkpoint.Height, checkpoint.Hash)
132
133 }
134
135 func main() {
136         // Load configuration and parse command line.
137         tcfg, _, err := loadConfig()
138         if err != nil {
139                 return
140         }
141         cfg = tcfg
142
143         // Load the block database.
144         db, err := loadBlockDB()
145         if err != nil {
146                 fmt.Fprintln(os.Stderr, "failed to load database:", err)
147                 return
148         }
149         defer db.Close()
150
151         // Setup chain.  Ignore notifications since they aren't needed for this
152         // util.
153         chain, err := blockchain.New(&blockchain.Config{
154                 DB:          db,
155                 ChainParams: activeNetParams,
156                 TimeSource:  blockchain.NewMedianTime(),
157         })
158         if err != nil {
159                 fmt.Fprintf(os.Stderr, "failed to initialize chain: %v\n", err)
160                 return
161         }
162
163         // Get the latest block hash and height from the database and report
164         // status.
165         best := chain.BestSnapshot()
166         fmt.Printf("Block database loaded with block height %d\n", best.Height)
167
168         // Find checkpoint candidates.
169         candidates, err := findCandidates(chain, &best.Hash)
170         if err != nil {
171                 fmt.Fprintln(os.Stderr, "Unable to identify candidates:", err)
172                 return
173         }
174
175         // No candidates.
176         if len(candidates) == 0 {
177                 fmt.Println("No candidates found.")
178                 return
179         }
180
181         // Show the candidates.
182         for i, checkpoint := range candidates {
183                 showCandidate(i+1, checkpoint)
184         }
185 }