1// Copyright (c) 2013-2017 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
5package blockchain
6
7import (
8	"fmt"
9	"time"
10
11	"github.com/btcsuite/btcd/chaincfg/chainhash"
12	"github.com/btcsuite/btcd/database"
13	"github.com/btcsuite/btcutil"
14)
15
16// BehaviorFlags is a bitmask defining tweaks to the normal behavior when
17// performing chain processing and consensus rules checks.
18type BehaviorFlags uint32
19
20const (
21	// BFFastAdd may be set to indicate that several checks can be avoided
22	// for the block since it is already known to fit into the chain due to
23	// already proving it correct links into the chain up to a known
24	// checkpoint.  This is primarily used for headers-first mode.
25	BFFastAdd BehaviorFlags = 1 << iota
26
27	// BFNoPoWCheck may be set to indicate the proof of work check which
28	// ensures a block hashes to a value less than the required target will
29	// not be performed.
30	BFNoPoWCheck
31
32	// BFNone is a convenience value to specifically indicate no flags.
33	BFNone BehaviorFlags = 0
34)
35
36// blockExists determines whether a block with the given hash exists either in
37// the main chain or any side chains.
38//
39// This function is safe for concurrent access.
40func (b *BlockChain) blockExists(hash *chainhash.Hash) (bool, error) {
41	// Check block index first (could be main chain or side chain blocks).
42	if b.index.HaveBlock(hash) {
43		return true, nil
44	}
45
46	// Check in the database.
47	var exists bool
48	err := b.db.View(func(dbTx database.Tx) error {
49		var err error
50		exists, err = dbTx.HasBlock(hash)
51		if err != nil || !exists {
52			return err
53		}
54
55		// Ignore side chain blocks in the database.  This is necessary
56		// because there is not currently any record of the associated
57		// block index data such as its block height, so it's not yet
58		// possible to efficiently load the block and do anything useful
59		// with it.
60		//
61		// Ultimately the entire block index should be serialized
62		// instead of only the current main chain so it can be consulted
63		// directly.
64		_, err = dbFetchHeightByHash(dbTx, hash)
65		if isNotInMainChainErr(err) {
66			exists = false
67			return nil
68		}
69		return err
70	})
71	return exists, err
72}
73
74// processOrphans determines if there are any orphans which depend on the passed
75// block hash (they are no longer orphans if true) and potentially accepts them.
76// It repeats the process for the newly accepted blocks (to detect further
77// orphans which may no longer be orphans) until there are no more.
78//
79// The flags do not modify the behavior of this function directly, however they
80// are needed to pass along to maybeAcceptBlock.
81//
82// This function MUST be called with the chain state lock held (for writes).
83func (b *BlockChain) processOrphans(hash *chainhash.Hash, flags BehaviorFlags) error {
84	// Start with processing at least the passed hash.  Leave a little room
85	// for additional orphan blocks that need to be processed without
86	// needing to grow the array in the common case.
87	processHashes := make([]*chainhash.Hash, 0, 10)
88	processHashes = append(processHashes, hash)
89	for len(processHashes) > 0 {
90		// Pop the first hash to process from the slice.
91		processHash := processHashes[0]
92		processHashes[0] = nil // Prevent GC leak.
93		processHashes = processHashes[1:]
94
95		// Look up all orphans that are parented by the block we just
96		// accepted.  This will typically only be one, but it could
97		// be multiple if multiple blocks are mined and broadcast
98		// around the same time.  The one with the most proof of work
99		// will eventually win out.  An indexing for loop is
100		// intentionally used over a range here as range does not
101		// reevaluate the slice on each iteration nor does it adjust the
102		// index for the modified slice.
103		for i := 0; i < len(b.prevOrphans[*processHash]); i++ {
104			orphan := b.prevOrphans[*processHash][i]
105			if orphan == nil {
106				log.Warnf("Found a nil entry at index %d in the "+
107					"orphan dependency list for block %v", i,
108					processHash)
109				continue
110			}
111
112			// Remove the orphan from the orphan pool.
113			orphanHash := orphan.block.Hash()
114			b.removeOrphanBlock(orphan)
115			i--
116
117			// Potentially accept the block into the block chain.
118			_, err := b.maybeAcceptBlock(orphan.block, flags)
119			if err != nil {
120				return err
121			}
122
123			// Add this block to the list of blocks to process so
124			// any orphan blocks that depend on this block are
125			// handled too.
126			processHashes = append(processHashes, orphanHash)
127		}
128	}
129	return nil
130}
131
132// ProcessBlock is the main workhorse for handling insertion of new blocks into
133// the block chain.  It includes functionality such as rejecting duplicate
134// blocks, ensuring blocks follow all rules, orphan handling, and insertion into
135// the block chain along with best chain selection and reorganization.
136//
137// When no errors occurred during processing, the first return value indicates
138// whether or not the block is on the main chain and the second indicates
139// whether or not the block is an orphan.
140//
141// This function is safe for concurrent access.
142func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bool, bool, error) {
143	b.chainLock.Lock()
144	defer b.chainLock.Unlock()
145
146	fastAdd := flags&BFFastAdd == BFFastAdd
147
148	blockHash := block.Hash()
149	log.Tracef("Processing block %v", blockHash)
150
151	// The block must not already exist in the main chain or side chains.
152	exists, err := b.blockExists(blockHash)
153	if err != nil {
154		return false, false, err
155	}
156	if exists {
157		str := fmt.Sprintf("already have block %v", blockHash)
158		return false, false, ruleError(ErrDuplicateBlock, str)
159	}
160
161	// The block must not already exist as an orphan.
162	if _, exists := b.orphans[*blockHash]; exists {
163		str := fmt.Sprintf("already have block (orphan) %v", blockHash)
164		return false, false, ruleError(ErrDuplicateBlock, str)
165	}
166
167	// Perform preliminary sanity checks on the block and its transactions.
168	err = checkBlockSanity(block, b.chainParams.PowLimit, b.timeSource, flags)
169	if err != nil {
170		return false, false, err
171	}
172
173	// Find the previous checkpoint and perform some additional checks based
174	// on the checkpoint.  This provides a few nice properties such as
175	// preventing old side chain blocks before the last checkpoint,
176	// rejecting easy to mine, but otherwise bogus, blocks that could be
177	// used to eat memory, and ensuring expected (versus claimed) proof of
178	// work requirements since the previous checkpoint are met.
179	blockHeader := &block.MsgBlock().Header
180	checkpointNode, err := b.findPreviousCheckpoint()
181	if err != nil {
182		return false, false, err
183	}
184	if checkpointNode != nil {
185		// Ensure the block timestamp is after the checkpoint timestamp.
186		checkpointTime := time.Unix(checkpointNode.timestamp, 0)
187		if blockHeader.Timestamp.Before(checkpointTime) {
188			str := fmt.Sprintf("block %v has timestamp %v before "+
189				"last checkpoint timestamp %v", blockHash,
190				blockHeader.Timestamp, checkpointTime)
191			return false, false, ruleError(ErrCheckpointTimeTooOld, str)
192		}
193		if !fastAdd {
194			// Even though the checks prior to now have already ensured the
195			// proof of work exceeds the claimed amount, the claimed amount
196			// is a field in the block header which could be forged.  This
197			// check ensures the proof of work is at least the minimum
198			// expected based on elapsed time since the last checkpoint and
199			// maximum adjustment allowed by the retarget rules.
200			duration := blockHeader.Timestamp.Sub(checkpointTime)
201			requiredTarget := CompactToBig(b.calcEasiestDifficulty(
202				checkpointNode.bits, duration))
203			currentTarget := CompactToBig(blockHeader.Bits)
204			if currentTarget.Cmp(requiredTarget) > 0 {
205				str := fmt.Sprintf("block target difficulty of %064x "+
206					"is too low when compared to the previous "+
207					"checkpoint", currentTarget)
208				return false, false, ruleError(ErrDifficultyTooLow, str)
209			}
210		}
211	}
212
213	// Handle orphan blocks.
214	prevHash := &blockHeader.PrevBlock
215	prevHashExists, err := b.blockExists(prevHash)
216	if err != nil {
217		return false, false, err
218	}
219	if !prevHashExists {
220		log.Infof("Adding orphan block %v with parent %v", blockHash, prevHash)
221		b.addOrphanBlock(block)
222
223		return false, true, nil
224	}
225
226	// The block has passed all context independent checks and appears sane
227	// enough to potentially accept it into the block chain.
228	isMainChain, err := b.maybeAcceptBlock(block, flags)
229	if err != nil {
230		return false, false, err
231	}
232
233	// Accept any orphan blocks that depend on this block (they are
234	// no longer orphans) and repeat for those accepted blocks until
235	// there are no more.
236	err = b.processOrphans(blockHash, flags)
237	if err != nil {
238		return false, false, err
239	}
240
241	log.Debugf("Accepted block %v", blockHash)
242
243	return isMainChain, false, nil
244}
245