1// Copyright (c) 2015-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
5package blockchain
6
7import (
8	"fmt"
9
10	"github.com/btcsuite/btcd/chaincfg/chainhash"
11	"github.com/btcsuite/btcd/database"
12	"github.com/btcsuite/btcd/txscript"
13	"github.com/btcsuite/btcd/wire"
14	"github.com/btcsuite/btcutil"
15)
16
17// txoFlags is a bitmask defining additional information and state for a
18// transaction output in a utxo view.
19type txoFlags uint8
20
21const (
22	// tfCoinBase indicates that a txout was contained in a coinbase tx.
23	tfCoinBase txoFlags = 1 << iota
24
25	// tfSpent indicates that a txout is spent.
26	tfSpent
27
28	// tfModified indicates that a txout has been modified since it was
29	// loaded.
30	tfModified
31)
32
33// UtxoEntry houses details about an individual transaction output in a utxo
34// view such as whether or not it was contained in a coinbase tx, the height of
35// the block that contains the tx, whether or not it is spent, its public key
36// script, and how much it pays.
37type UtxoEntry struct {
38	// NOTE: Additions, deletions, or modifications to the order of the
39	// definitions in this struct should not be changed without considering
40	// how it affects alignment on 64-bit platforms.  The current order is
41	// specifically crafted to result in minimal padding.  There will be a
42	// lot of these in memory, so a few extra bytes of padding adds up.
43
44	amount      int64
45	pkScript    []byte // The public key script for the output.
46	blockHeight int32  // Height of block containing tx.
47
48	// packedFlags contains additional info about output such as whether it
49	// is a coinbase, whether it is spent, and whether it has been modified
50	// since it was loaded.  This approach is used in order to reduce memory
51	// usage since there will be a lot of these in memory.
52	packedFlags txoFlags
53}
54
55// isModified returns whether or not the output has been modified since it was
56// loaded.
57func (entry *UtxoEntry) isModified() bool {
58	return entry.packedFlags&tfModified == tfModified
59}
60
61// IsCoinBase returns whether or not the output was contained in a coinbase
62// transaction.
63func (entry *UtxoEntry) IsCoinBase() bool {
64	return entry.packedFlags&tfCoinBase == tfCoinBase
65}
66
67// BlockHeight returns the height of the block containing the output.
68func (entry *UtxoEntry) BlockHeight() int32 {
69	return entry.blockHeight
70}
71
72// IsSpent returns whether or not the output has been spent based upon the
73// current state of the unspent transaction output view it was obtained from.
74func (entry *UtxoEntry) IsSpent() bool {
75	return entry.packedFlags&tfSpent == tfSpent
76}
77
78// Spend marks the output as spent.  Spending an output that is already spent
79// has no effect.
80func (entry *UtxoEntry) Spend() {
81	// Nothing to do if the output is already spent.
82	if entry.IsSpent() {
83		return
84	}
85
86	// Mark the output as spent and modified.
87	entry.packedFlags |= tfSpent | tfModified
88}
89
90// Amount returns the amount of the output.
91func (entry *UtxoEntry) Amount() int64 {
92	return entry.amount
93}
94
95// PkScript returns the public key script for the output.
96func (entry *UtxoEntry) PkScript() []byte {
97	return entry.pkScript
98}
99
100// Clone returns a shallow copy of the utxo entry.
101func (entry *UtxoEntry) Clone() *UtxoEntry {
102	if entry == nil {
103		return nil
104	}
105
106	return &UtxoEntry{
107		amount:      entry.amount,
108		pkScript:    entry.pkScript,
109		blockHeight: entry.blockHeight,
110		packedFlags: entry.packedFlags,
111	}
112}
113
114// UtxoViewpoint represents a view into the set of unspent transaction outputs
115// from a specific point of view in the chain.  For example, it could be for
116// the end of the main chain, some point in the history of the main chain, or
117// down a side chain.
118//
119// The unspent outputs are needed by other transactions for things such as
120// script validation and double spend prevention.
121type UtxoViewpoint struct {
122	entries  map[wire.OutPoint]*UtxoEntry
123	bestHash chainhash.Hash
124}
125
126// BestHash returns the hash of the best block in the chain the view currently
127// respresents.
128func (view *UtxoViewpoint) BestHash() *chainhash.Hash {
129	return &view.bestHash
130}
131
132// SetBestHash sets the hash of the best block in the chain the view currently
133// respresents.
134func (view *UtxoViewpoint) SetBestHash(hash *chainhash.Hash) {
135	view.bestHash = *hash
136}
137
138// LookupEntry returns information about a given transaction output according to
139// the current state of the view.  It will return nil if the passed output does
140// not exist in the view or is otherwise not available such as when it has been
141// disconnected during a reorg.
142func (view *UtxoViewpoint) LookupEntry(outpoint wire.OutPoint) *UtxoEntry {
143	return view.entries[outpoint]
144}
145
146// addTxOut adds the specified output to the view if it is not provably
147// unspendable.  When the view already has an entry for the output, it will be
148// marked unspent.  All fields will be updated for existing entries since it's
149// possible it has changed during a reorg.
150func (view *UtxoViewpoint) addTxOut(outpoint wire.OutPoint, txOut *wire.TxOut, isCoinBase bool, blockHeight int32) {
151	// Don't add provably unspendable outputs.
152	if txscript.IsUnspendable(txOut.PkScript) {
153		return
154	}
155
156	// Update existing entries.  All fields are updated because it's
157	// possible (although extremely unlikely) that the existing entry is
158	// being replaced by a different transaction with the same hash.  This
159	// is allowed so long as the previous transaction is fully spent.
160	entry := view.LookupEntry(outpoint)
161	if entry == nil {
162		entry = new(UtxoEntry)
163		view.entries[outpoint] = entry
164	}
165
166	entry.amount = txOut.Value
167	entry.pkScript = txOut.PkScript
168	entry.blockHeight = blockHeight
169	entry.packedFlags = tfModified
170	if isCoinBase {
171		entry.packedFlags |= tfCoinBase
172	}
173}
174
175// AddTxOut adds the specified output of the passed transaction to the view if
176// it exists and is not provably unspendable.  When the view already has an
177// entry for the output, it will be marked unspent.  All fields will be updated
178// for existing entries since it's possible it has changed during a reorg.
179func (view *UtxoViewpoint) AddTxOut(tx *btcutil.Tx, txOutIdx uint32, blockHeight int32) {
180	// Can't add an output for an out of bounds index.
181	if txOutIdx >= uint32(len(tx.MsgTx().TxOut)) {
182		return
183	}
184
185	// Update existing entries.  All fields are updated because it's
186	// possible (although extremely unlikely) that the existing entry is
187	// being replaced by a different transaction with the same hash.  This
188	// is allowed so long as the previous transaction is fully spent.
189	prevOut := wire.OutPoint{Hash: *tx.Hash(), Index: txOutIdx}
190	txOut := tx.MsgTx().TxOut[txOutIdx]
191	view.addTxOut(prevOut, txOut, IsCoinBase(tx), blockHeight)
192}
193
194// AddTxOuts adds all outputs in the passed transaction which are not provably
195// unspendable to the view.  When the view already has entries for any of the
196// outputs, they are simply marked unspent.  All fields will be updated for
197// existing entries since it's possible it has changed during a reorg.
198func (view *UtxoViewpoint) AddTxOuts(tx *btcutil.Tx, blockHeight int32) {
199	// Loop all of the transaction outputs and add those which are not
200	// provably unspendable.
201	isCoinBase := IsCoinBase(tx)
202	prevOut := wire.OutPoint{Hash: *tx.Hash()}
203	for txOutIdx, txOut := range tx.MsgTx().TxOut {
204		// Update existing entries.  All fields are updated because it's
205		// possible (although extremely unlikely) that the existing
206		// entry is being replaced by a different transaction with the
207		// same hash.  This is allowed so long as the previous
208		// transaction is fully spent.
209		prevOut.Index = uint32(txOutIdx)
210		view.addTxOut(prevOut, txOut, isCoinBase, blockHeight)
211	}
212}
213
214// connectTransaction updates the view by adding all new utxos created by the
215// passed transaction and marking all utxos that the transactions spend as
216// spent.  In addition, when the 'stxos' argument is not nil, it will be updated
217// to append an entry for each spent txout.  An error will be returned if the
218// view does not contain the required utxos.
219func (view *UtxoViewpoint) connectTransaction(tx *btcutil.Tx, blockHeight int32, stxos *[]SpentTxOut) error {
220	// Coinbase transactions don't have any inputs to spend.
221	if IsCoinBase(tx) {
222		// Add the transaction's outputs as available utxos.
223		view.AddTxOuts(tx, blockHeight)
224		return nil
225	}
226
227	// Spend the referenced utxos by marking them spent in the view and,
228	// if a slice was provided for the spent txout details, append an entry
229	// to it.
230	for _, txIn := range tx.MsgTx().TxIn {
231		// Ensure the referenced utxo exists in the view.  This should
232		// never happen unless there is a bug is introduced in the code.
233		entry := view.entries[txIn.PreviousOutPoint]
234		if entry == nil {
235			return AssertError(fmt.Sprintf("view missing input %v",
236				txIn.PreviousOutPoint))
237		}
238
239		// Only create the stxo details if requested.
240		if stxos != nil {
241			// Populate the stxo details using the utxo entry.
242			var stxo = SpentTxOut{
243				Amount:     entry.Amount(),
244				PkScript:   entry.PkScript(),
245				Height:     entry.BlockHeight(),
246				IsCoinBase: entry.IsCoinBase(),
247			}
248			*stxos = append(*stxos, stxo)
249		}
250
251		// Mark the entry as spent.  This is not done until after the
252		// relevant details have been accessed since spending it might
253		// clear the fields from memory in the future.
254		entry.Spend()
255	}
256
257	// Add the transaction's outputs as available utxos.
258	view.AddTxOuts(tx, blockHeight)
259	return nil
260}
261
262// connectTransactions updates the view by adding all new utxos created by all
263// of the transactions in the passed block, marking all utxos the transactions
264// spend as spent, and setting the best hash for the view to the passed block.
265// In addition, when the 'stxos' argument is not nil, it will be updated to
266// append an entry for each spent txout.
267func (view *UtxoViewpoint) connectTransactions(block *btcutil.Block, stxos *[]SpentTxOut) error {
268	for _, tx := range block.Transactions() {
269		err := view.connectTransaction(tx, block.Height(), stxos)
270		if err != nil {
271			return err
272		}
273	}
274
275	// Update the best hash for view to include this block since all of its
276	// transactions have been connected.
277	view.SetBestHash(block.Hash())
278	return nil
279}
280
281// fetchEntryByHash attempts to find any available utxo for the given hash by
282// searching the entire set of possible outputs for the given hash.  It checks
283// the view first and then falls back to the database if needed.
284func (view *UtxoViewpoint) fetchEntryByHash(db database.DB, hash *chainhash.Hash) (*UtxoEntry, error) {
285	// First attempt to find a utxo with the provided hash in the view.
286	prevOut := wire.OutPoint{Hash: *hash}
287	for idx := uint32(0); idx < MaxOutputsPerBlock; idx++ {
288		prevOut.Index = idx
289		entry := view.LookupEntry(prevOut)
290		if entry != nil {
291			return entry, nil
292		}
293	}
294
295	// Check the database since it doesn't exist in the view.  This will
296	// often by the case since only specifically referenced utxos are loaded
297	// into the view.
298	var entry *UtxoEntry
299	err := db.View(func(dbTx database.Tx) error {
300		var err error
301		entry, err = dbFetchUtxoEntryByHash(dbTx, hash)
302		return err
303	})
304	return entry, err
305}
306
307// disconnectTransactions updates the view by removing all of the transactions
308// created by the passed block, restoring all utxos the transactions spent by
309// using the provided spent txo information, and setting the best hash for the
310// view to the block before the passed block.
311func (view *UtxoViewpoint) disconnectTransactions(db database.DB, block *btcutil.Block, stxos []SpentTxOut) error {
312	// Sanity check the correct number of stxos are provided.
313	if len(stxos) != countSpentOutputs(block) {
314		return AssertError("disconnectTransactions called with bad " +
315			"spent transaction out information")
316	}
317
318	// Loop backwards through all transactions so everything is unspent in
319	// reverse order.  This is necessary since transactions later in a block
320	// can spend from previous ones.
321	stxoIdx := len(stxos) - 1
322	transactions := block.Transactions()
323	for txIdx := len(transactions) - 1; txIdx > -1; txIdx-- {
324		tx := transactions[txIdx]
325
326		// All entries will need to potentially be marked as a coinbase.
327		var packedFlags txoFlags
328		isCoinBase := txIdx == 0
329		if isCoinBase {
330			packedFlags |= tfCoinBase
331		}
332
333		// Mark all of the spendable outputs originally created by the
334		// transaction as spent.  It is instructive to note that while
335		// the outputs aren't actually being spent here, rather they no
336		// longer exist, since a pruned utxo set is used, there is no
337		// practical difference between a utxo that does not exist and
338		// one that has been spent.
339		//
340		// When the utxo does not already exist in the view, add an
341		// entry for it and then mark it spent.  This is done because
342		// the code relies on its existence in the view in order to
343		// signal modifications have happened.
344		txHash := tx.Hash()
345		prevOut := wire.OutPoint{Hash: *txHash}
346		for txOutIdx, txOut := range tx.MsgTx().TxOut {
347			if txscript.IsUnspendable(txOut.PkScript) {
348				continue
349			}
350
351			prevOut.Index = uint32(txOutIdx)
352			entry := view.entries[prevOut]
353			if entry == nil {
354				entry = &UtxoEntry{
355					amount:      txOut.Value,
356					pkScript:    txOut.PkScript,
357					blockHeight: block.Height(),
358					packedFlags: packedFlags,
359				}
360
361				view.entries[prevOut] = entry
362			}
363
364			entry.Spend()
365		}
366
367		// Loop backwards through all of the transaction inputs (except
368		// for the coinbase which has no inputs) and unspend the
369		// referenced txos.  This is necessary to match the order of the
370		// spent txout entries.
371		if isCoinBase {
372			continue
373		}
374		for txInIdx := len(tx.MsgTx().TxIn) - 1; txInIdx > -1; txInIdx-- {
375			// Ensure the spent txout index is decremented to stay
376			// in sync with the transaction input.
377			stxo := &stxos[stxoIdx]
378			stxoIdx--
379
380			// When there is not already an entry for the referenced
381			// output in the view, it means it was previously spent,
382			// so create a new utxo entry in order to resurrect it.
383			originOut := &tx.MsgTx().TxIn[txInIdx].PreviousOutPoint
384			entry := view.entries[*originOut]
385			if entry == nil {
386				entry = new(UtxoEntry)
387				view.entries[*originOut] = entry
388			}
389
390			// The legacy v1 spend journal format only stored the
391			// coinbase flag and height when the output was the last
392			// unspent output of the transaction.  As a result, when
393			// the information is missing, search for it by scanning
394			// all possible outputs of the transaction since it must
395			// be in one of them.
396			//
397			// It should be noted that this is quite inefficient,
398			// but it realistically will almost never run since all
399			// new entries include the information for all outputs
400			// and thus the only way this will be hit is if a long
401			// enough reorg happens such that a block with the old
402			// spend data is being disconnected.  The probability of
403			// that in practice is extremely low to begin with and
404			// becomes vanishingly small the more new blocks are
405			// connected.  In the case of a fresh database that has
406			// only ever run with the new v2 format, this code path
407			// will never run.
408			if stxo.Height == 0 {
409				utxo, err := view.fetchEntryByHash(db, txHash)
410				if err != nil {
411					return err
412				}
413				if utxo == nil {
414					return AssertError(fmt.Sprintf("unable "+
415						"to resurrect legacy stxo %v",
416						*originOut))
417				}
418
419				stxo.Height = utxo.BlockHeight()
420				stxo.IsCoinBase = utxo.IsCoinBase()
421			}
422
423			// Restore the utxo using the stxo data from the spend
424			// journal and mark it as modified.
425			entry.amount = stxo.Amount
426			entry.pkScript = stxo.PkScript
427			entry.blockHeight = stxo.Height
428			entry.packedFlags = tfModified
429			if stxo.IsCoinBase {
430				entry.packedFlags |= tfCoinBase
431			}
432		}
433	}
434
435	// Update the best hash for view to the previous block since all of the
436	// transactions for the current block have been disconnected.
437	view.SetBestHash(&block.MsgBlock().Header.PrevBlock)
438	return nil
439}
440
441// RemoveEntry removes the given transaction output from the current state of
442// the view.  It will have no effect if the passed output does not exist in the
443// view.
444func (view *UtxoViewpoint) RemoveEntry(outpoint wire.OutPoint) {
445	delete(view.entries, outpoint)
446}
447
448// Entries returns the underlying map that stores of all the utxo entries.
449func (view *UtxoViewpoint) Entries() map[wire.OutPoint]*UtxoEntry {
450	return view.entries
451}
452
453// commit prunes all entries marked modified that are now fully spent and marks
454// all entries as unmodified.
455func (view *UtxoViewpoint) commit() {
456	for outpoint, entry := range view.entries {
457		if entry == nil || (entry.isModified() && entry.IsSpent()) {
458			delete(view.entries, outpoint)
459			continue
460		}
461
462		entry.packedFlags ^= tfModified
463	}
464}
465
466// fetchUtxosMain fetches unspent transaction output data about the provided
467// set of outpoints from the point of view of the end of the main chain at the
468// time of the call.
469//
470// Upon completion of this function, the view will contain an entry for each
471// requested outpoint.  Spent outputs, or those which otherwise don't exist,
472// will result in a nil entry in the view.
473func (view *UtxoViewpoint) fetchUtxosMain(db database.DB, outpoints map[wire.OutPoint]struct{}) error {
474	// Nothing to do if there are no requested outputs.
475	if len(outpoints) == 0 {
476		return nil
477	}
478
479	// Load the requested set of unspent transaction outputs from the point
480	// of view of the end of the main chain.
481	//
482	// NOTE: Missing entries are not considered an error here and instead
483	// will result in nil entries in the view.  This is intentionally done
484	// so other code can use the presence of an entry in the store as a way
485	// to unnecessarily avoid attempting to reload it from the database.
486	return db.View(func(dbTx database.Tx) error {
487		for outpoint := range outpoints {
488			entry, err := dbFetchUtxoEntry(dbTx, outpoint)
489			if err != nil {
490				return err
491			}
492
493			view.entries[outpoint] = entry
494		}
495
496		return nil
497	})
498}
499
500// fetchUtxos loads the unspent transaction outputs for the provided set of
501// outputs into the view from the database as needed unless they already exist
502// in the view in which case they are ignored.
503func (view *UtxoViewpoint) fetchUtxos(db database.DB, outpoints map[wire.OutPoint]struct{}) error {
504	// Nothing to do if there are no requested outputs.
505	if len(outpoints) == 0 {
506		return nil
507	}
508
509	// Filter entries that are already in the view.
510	neededSet := make(map[wire.OutPoint]struct{})
511	for outpoint := range outpoints {
512		// Already loaded into the current view.
513		if _, ok := view.entries[outpoint]; ok {
514			continue
515		}
516
517		neededSet[outpoint] = struct{}{}
518	}
519
520	// Request the input utxos from the database.
521	return view.fetchUtxosMain(db, neededSet)
522}
523
524// fetchInputUtxos loads the unspent transaction outputs for the inputs
525// referenced by the transactions in the given block into the view from the
526// database as needed.  In particular, referenced entries that are earlier in
527// the block are added to the view and entries that are already in the view are
528// not modified.
529func (view *UtxoViewpoint) fetchInputUtxos(db database.DB, block *btcutil.Block) error {
530	// Build a map of in-flight transactions because some of the inputs in
531	// this block could be referencing other transactions earlier in this
532	// block which are not yet in the chain.
533	txInFlight := map[chainhash.Hash]int{}
534	transactions := block.Transactions()
535	for i, tx := range transactions {
536		txInFlight[*tx.Hash()] = i
537	}
538
539	// Loop through all of the transaction inputs (except for the coinbase
540	// which has no inputs) collecting them into sets of what is needed and
541	// what is already known (in-flight).
542	neededSet := make(map[wire.OutPoint]struct{})
543	for i, tx := range transactions[1:] {
544		for _, txIn := range tx.MsgTx().TxIn {
545			// It is acceptable for a transaction input to reference
546			// the output of another transaction in this block only
547			// if the referenced transaction comes before the
548			// current one in this block.  Add the outputs of the
549			// referenced transaction as available utxos when this
550			// is the case.  Otherwise, the utxo details are still
551			// needed.
552			//
553			// NOTE: The >= is correct here because i is one less
554			// than the actual position of the transaction within
555			// the block due to skipping the coinbase.
556			originHash := &txIn.PreviousOutPoint.Hash
557			if inFlightIndex, ok := txInFlight[*originHash]; ok &&
558				i >= inFlightIndex {
559
560				originTx := transactions[inFlightIndex]
561				view.AddTxOuts(originTx, block.Height())
562				continue
563			}
564
565			// Don't request entries that are already in the view
566			// from the database.
567			if _, ok := view.entries[txIn.PreviousOutPoint]; ok {
568				continue
569			}
570
571			neededSet[txIn.PreviousOutPoint] = struct{}{}
572		}
573	}
574
575	// Request the input utxos from the database.
576	return view.fetchUtxosMain(db, neededSet)
577}
578
579// NewUtxoViewpoint returns a new empty unspent transaction output view.
580func NewUtxoViewpoint() *UtxoViewpoint {
581	return &UtxoViewpoint{
582		entries: make(map[wire.OutPoint]*UtxoEntry),
583	}
584}
585
586// FetchUtxoView loads unspent transaction outputs for the inputs referenced by
587// the passed transaction from the point of view of the end of the main chain.
588// It also attempts to fetch the utxos for the outputs of the transaction itself
589// so the returned view can be examined for duplicate transactions.
590//
591// This function is safe for concurrent access however the returned view is NOT.
592func (b *BlockChain) FetchUtxoView(tx *btcutil.Tx) (*UtxoViewpoint, error) {
593	// Create a set of needed outputs based on those referenced by the
594	// inputs of the passed transaction and the outputs of the transaction
595	// itself.
596	neededSet := make(map[wire.OutPoint]struct{})
597	prevOut := wire.OutPoint{Hash: *tx.Hash()}
598	for txOutIdx := range tx.MsgTx().TxOut {
599		prevOut.Index = uint32(txOutIdx)
600		neededSet[prevOut] = struct{}{}
601	}
602	if !IsCoinBase(tx) {
603		for _, txIn := range tx.MsgTx().TxIn {
604			neededSet[txIn.PreviousOutPoint] = struct{}{}
605		}
606	}
607
608	// Request the utxos from the point of view of the end of the main
609	// chain.
610	view := NewUtxoViewpoint()
611	b.chainLock.RLock()
612	err := view.fetchUtxosMain(b.db, neededSet)
613	b.chainLock.RUnlock()
614	return view, err
615}
616
617// FetchUtxoEntry loads and returns the requested unspent transaction output
618// from the point of view of the end of the main chain.
619//
620// NOTE: Requesting an output for which there is no data will NOT return an
621// error.  Instead both the entry and the error will be nil.  This is done to
622// allow pruning of spent transaction outputs.  In practice this means the
623// caller must check if the returned entry is nil before invoking methods on it.
624//
625// This function is safe for concurrent access however the returned entry (if
626// any) is NOT.
627func (b *BlockChain) FetchUtxoEntry(outpoint wire.OutPoint) (*UtxoEntry, error) {
628	b.chainLock.RLock()
629	defer b.chainLock.RUnlock()
630
631	var entry *UtxoEntry
632	err := b.db.View(func(dbTx database.Tx) error {
633		var err error
634		entry, err = dbFetchUtxoEntry(dbTx, outpoint)
635		return err
636	})
637	if err != nil {
638		return nil, err
639	}
640
641	return entry, nil
642}
643