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