Allow tx inputs to use txns earlier in same block.

It is acceptable for a transaction input in a block to reference the
output of another transaction in the same block only if the referenced
transaction comes before the transaction referencing it.
This commit is contained in:
Dave Collins 2013-07-29 15:48:52 -05:00
parent e82c97be3b
commit c3b330e42d

View file

@ -193,16 +193,17 @@ func (b *BlockChain) fetchTxList(node *blockNode, txList []*btcwire.ShaHash) (ma
// for more details on what the point of view entails. // for more details on what the point of view entails.
func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Block) (map[btcwire.ShaHash]*txData, error) { func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Block) (map[btcwire.ShaHash]*txData, error) {
// Build a map of in-flight transactions because some of the inputs in // Build a map of in-flight transactions because some of the inputs in
// this block could be referencing other transactions in this block // this block could be referencing other transactions earlier in this
// which are not yet in the chain. // block which are not yet in the chain.
txInFlight := map[btcwire.ShaHash]*btcwire.MsgTx{} txInFlight := map[btcwire.ShaHash]int{}
for i, tx := range block.MsgBlock().Transactions { transactions := block.MsgBlock().Transactions
for i := range transactions {
// Get transaction hash. It's safe to ignore the error since // Get transaction hash. It's safe to ignore the error since
// it's already cached in the nominal code path and the only // it's already cached in the nominal code path and the only
// way it can fail is if the index is out of range which is // way it can fail is if the index is out of range which is
// impossible here. // impossible here.
txHash, _ := block.TxSha(i) txHash, _ := block.TxSha(i)
txInFlight[*txHash] = tx txInFlight[*txHash] = i
} }
// Loop through all of the transaction inputs (except for the coinbase // Loop through all of the transaction inputs (except for the coinbase
@ -210,7 +211,7 @@ func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Bloc
// what is already known (in-flight). // what is already known (in-flight).
var txNeededList []*btcwire.ShaHash var txNeededList []*btcwire.ShaHash
txStore := make(map[btcwire.ShaHash]*txData) txStore := make(map[btcwire.ShaHash]*txData)
for _, tx := range block.MsgBlock().Transactions[1:] { for i, tx := range transactions[1:] {
for _, txIn := range tx.TxIn { for _, txIn := range tx.TxIn {
// Add an entry to the transaction store for the needed // Add an entry to the transaction store for the needed
// transaction with it set to missing by default. // transaction with it set to missing by default.
@ -218,13 +219,23 @@ func (b *BlockChain) fetchInputTransactions(node *blockNode, block *btcutil.Bloc
txD := &txData{hash: originHash, err: btcdb.TxShaMissing} txD := &txData{hash: originHash, err: btcdb.TxShaMissing}
txStore[*originHash] = txD txStore[*originHash] = txD
// The transaction is already in-flight, so update the // It is acceptable for a transaction input to reference
// transaction store acccordingly. Otherwise, we need // the output of another transaction in this block only
// it. // if the referenced transaction comes before the
if tx, ok := txInFlight[*originHash]; ok { // current one in this block. Update the transaction
txD.tx = tx // store acccordingly when this is the case. Otherwise,
// we still need the transaction.
//
// NOTE: The >= is correct here because i is one less
// than the actual position of the transaction within
// the block due to skipping the coinbase.
if inFlightIndex, ok := txInFlight[*originHash]; ok &&
i >= inFlightIndex {
originTx := transactions[inFlightIndex]
txD.tx = originTx
txD.blockHeight = node.height txD.blockHeight = node.height
txD.spent = make([]bool, len(tx.TxOut)) txD.spent = make([]bool, len(originTx.TxOut))
txD.err = nil txD.err = nil
} else { } else {
txNeededList = append(txNeededList, originHash) txNeededList = append(txNeededList, originHash)