OSDN Git Service

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