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.
11 "github.com/btcsuite/btcd/chaincfg"
12 "github.com/btcsuite/btcd/chaincfg/chainhash"
13 "github.com/btcsuite/btcd/txscript"
14 "github.com/btcsuite/btcutil"
17 // CheckpointConfirmations is the number of blocks before the end of the current
18 // best block chain that a good checkpoint candidate must be.
19 const CheckpointConfirmations = 2016
21 // newHashFromStr converts the passed big-endian hex string into a
22 // chainhash.Hash. It only differs from the one available in chainhash in that
23 // it ignores the error since it will only (and must only) be called with
24 // hard-coded, and therefore known good, hashes.
25 func newHashFromStr(hexStr string) *chainhash.Hash {
26 hash, _ := chainhash.NewHashFromStr(hexStr)
30 // Checkpoints returns a slice of checkpoints (regardless of whether they are
31 // already known). When there are no checkpoints for the chain, it will return
34 // This function is safe for concurrent access.
35 func (b *BlockChain) Checkpoints() []chaincfg.Checkpoint {
39 // HasCheckpoints returns whether this BlockChain has checkpoints defined.
41 // This function is safe for concurrent access.
42 func (b *BlockChain) HasCheckpoints() bool {
43 return len(b.checkpoints) > 0
46 // LatestCheckpoint returns the most recent checkpoint (regardless of whether it
47 // is already known). When there are no defined checkpoints for the active chain
48 // instance, it will return nil.
50 // This function is safe for concurrent access.
51 func (b *BlockChain) LatestCheckpoint() *chaincfg.Checkpoint {
52 if !b.HasCheckpoints() {
55 return &b.checkpoints[len(b.checkpoints)-1]
58 // verifyCheckpoint returns whether the passed block height and hash combination
59 // match the checkpoint data. It also returns true if there is no checkpoint
60 // data for the passed block height.
61 func (b *BlockChain) verifyCheckpoint(height int32, hash *chainhash.Hash) bool {
62 if !b.HasCheckpoints() {
66 // Nothing to check if there is no checkpoint data for the block height.
67 checkpoint, exists := b.checkpointsByHeight[height]
72 if !checkpoint.Hash.IsEqual(hash) {
76 log.Infof("Verified checkpoint at height %d/block %s", checkpoint.Height,
81 // findPreviousCheckpoint finds the most recent checkpoint that is already
82 // available in the downloaded portion of the block chain and returns the
83 // associated block node. It returns nil if a checkpoint can't be found (this
84 // should really only happen for blocks before the first checkpoint).
86 // This function MUST be called with the chain lock held (for reads).
87 func (b *BlockChain) findPreviousCheckpoint() (*blockNode, error) {
88 if !b.HasCheckpoints() {
92 // Perform the initial search to find and cache the latest known
93 // checkpoint if the best chain is not known yet or we haven't already
94 // previously searched.
95 checkpoints := b.checkpoints
96 numCheckpoints := len(checkpoints)
97 if b.checkpointNode == nil && b.nextCheckpoint == nil {
98 // Loop backwards through the available checkpoints to find one
99 // that is already available.
100 for i := numCheckpoints - 1; i >= 0; i-- {
101 node := b.index.LookupNode(checkpoints[i].Hash)
102 if node == nil || !b.bestChain.Contains(node) {
106 // Checkpoint found. Cache it for future lookups and
107 // set the next expected checkpoint accordingly.
108 b.checkpointNode = node
109 if i < numCheckpoints-1 {
110 b.nextCheckpoint = &checkpoints[i+1]
112 return b.checkpointNode, nil
115 // No known latest checkpoint. This will only happen on blocks
116 // before the first known checkpoint. So, set the next expected
117 // checkpoint to the first checkpoint and return the fact there
118 // is no latest known checkpoint block.
119 b.nextCheckpoint = &checkpoints[0]
123 // At this point we've already searched for the latest known checkpoint,
124 // so when there is no next checkpoint, the current checkpoint lockin
125 // will always be the latest known checkpoint.
126 if b.nextCheckpoint == nil {
127 return b.checkpointNode, nil
130 // When there is a next checkpoint and the height of the current best
131 // chain does not exceed it, the current checkpoint lockin is still
132 // the latest known checkpoint.
133 if b.bestChain.Tip().height < b.nextCheckpoint.Height {
134 return b.checkpointNode, nil
137 // We've reached or exceeded the next checkpoint height. Note that
138 // once a checkpoint lockin has been reached, forks are prevented from
139 // any blocks before the checkpoint, so we don't have to worry about the
140 // checkpoint going away out from under us due to a chain reorganize.
142 // Cache the latest known checkpoint for future lookups. Note that if
143 // this lookup fails something is very wrong since the chain has already
144 // passed the checkpoint which was verified as accurate before inserting
146 checkpointNode := b.index.LookupNode(b.nextCheckpoint.Hash)
147 if checkpointNode == nil {
148 return nil, AssertError(fmt.Sprintf("findPreviousCheckpoint "+
149 "failed lookup of known good block node %s",
150 b.nextCheckpoint.Hash))
152 b.checkpointNode = checkpointNode
154 // Set the next expected checkpoint.
155 checkpointIndex := -1
156 for i := numCheckpoints - 1; i >= 0; i-- {
157 if checkpoints[i].Hash.IsEqual(b.nextCheckpoint.Hash) {
162 b.nextCheckpoint = nil
163 if checkpointIndex != -1 && checkpointIndex < numCheckpoints-1 {
164 b.nextCheckpoint = &checkpoints[checkpointIndex+1]
167 return b.checkpointNode, nil
170 // isNonstandardTransaction determines whether a transaction contains any
171 // scripts which are not one of the standard types.
172 func isNonstandardTransaction(tx *btcutil.Tx) bool {
173 // Check all of the output public key scripts for non-standard scripts.
174 for _, txOut := range tx.MsgTx().TxOut {
175 scriptClass := txscript.GetScriptClass(txOut.PkScript)
176 if scriptClass == txscript.NonStandardTy {
183 // IsCheckpointCandidate returns whether or not the passed block is a good
184 // checkpoint candidate.
186 // The factors used to determine a good checkpoint are:
187 // - The block must be in the main chain
188 // - The block must be at least 'CheckpointConfirmations' blocks prior to the
189 // current end of the main chain
190 // - The timestamps for the blocks before and after the checkpoint must have
191 // timestamps which are also before and after the checkpoint, respectively
192 // (due to the median time allowance this is not always the case)
193 // - The block must not contain any strange transaction such as those with
194 // nonstandard scripts
196 // The intent is that candidates are reviewed by a developer to make the final
197 // decision and then manually added to the list of checkpoints for a network.
199 // This function is safe for concurrent access.
200 func (b *BlockChain) IsCheckpointCandidate(block *btcutil.Block) (bool, error) {
202 defer b.chainLock.RUnlock()
204 // A checkpoint must be in the main chain.
205 node := b.index.LookupNode(block.Hash())
206 if node == nil || !b.bestChain.Contains(node) {
210 // Ensure the height of the passed block and the entry for the block in
211 // the main chain match. This should always be the case unless the
212 // caller provided an invalid block.
213 if node.height != block.Height() {
214 return false, fmt.Errorf("passed block height of %d does not "+
215 "match the main chain height of %d", block.Height(),
219 // A checkpoint must be at least CheckpointConfirmations blocks
220 // before the end of the main chain.
221 mainChainHeight := b.bestChain.Tip().height
222 if node.height > (mainChainHeight - CheckpointConfirmations) {
226 // A checkpoint must be have at least one block after it.
228 // This should always succeed since the check above already made sure it
229 // is CheckpointConfirmations back, but be safe in case the constant
231 nextNode := b.bestChain.Next(node)
236 // A checkpoint must be have at least one block before it.
237 if node.parent == nil {
241 // A checkpoint must have timestamps for the block and the blocks on
242 // either side of it in order (due to the median time allowance this is
243 // not always the case).
244 prevTime := time.Unix(node.parent.timestamp, 0)
245 curTime := block.MsgBlock().Header.Timestamp
246 nextTime := time.Unix(nextNode.timestamp, 0)
247 if prevTime.After(curTime) || nextTime.Before(curTime) {
251 // A checkpoint must have transactions that only contain standard
253 for _, tx := range block.Transactions() {
254 if isNonstandardTransaction(tx) {
259 // All of the checks passed, so the block is a candidate.