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