From 4696d16ed421fc1ce0fe688e66d88872581a1e5e Mon Sep 17 00:00:00 2001
From: cjepson <info@companyzero.com>
Date: Mon, 30 Mar 2015 13:16:23 -0400
Subject: [PATCH] Fix race in FetchTransactionStore

Because FetchTransactionStore in GetBlockTemplate occasionally accesses
the internal blockchain memory structure while it is being read or modified,
a race can occur. To prevent this, FetchTransactionStore is instead
routed through the internal channel for blockchain requests.
---
 blockmanager.go | 30 ++++++++++++++++++++++++++++++
 mining.go       |  3 +--
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/blockmanager.go b/blockmanager.go
index cb72fe2f..1f5250b7 100644
--- a/blockmanager.go
+++ b/blockmanager.go
@@ -107,6 +107,20 @@ type processBlockResponse struct {
 	err      error
 }
 
+// fetchTransactionStoreResponse is a response sent to the reply channel of a
+// fetchTransactionStoreMsg.
+type fetchTransactionStoreResponse struct {
+	TxStore blockchain.TxStore
+	err     error
+}
+
+// fetchTransactionStoreMsg is a message type to be sent across the message
+// channel fetching the tx input store for some Tx.
+type fetchTransactionStoreMsg struct {
+	tx    *btcutil.Tx
+	reply chan fetchTransactionStoreResponse
+}
+
 // processBlockMsg is a message type to be sent across the message channel
 // for requested a block is processed.  Note this call differs from blockMsg
 // above in that blockMsg is intended for blocks that came from peers and have
@@ -1109,6 +1123,13 @@ out:
 					err:        err,
 				}
 
+			case fetchTransactionStoreMsg:
+				txStore, err := b.blockChain.FetchTransactionStore(msg.tx)
+				msg.reply <- fetchTransactionStoreResponse{
+					TxStore: txStore,
+					err:     err,
+				}
+
 			case processBlockMsg:
 				isOrphan, err := b.blockChain.ProcessBlock(
 					msg.block, b.server.timeSource,
@@ -1371,6 +1392,15 @@ func (b *blockManager) CalcNextRequiredDifficulty(timestamp time.Time) (uint32,
 	return response.difficulty, response.err
 }
 
+// FetchTransactionStore makes use of FetchTransactionStore on an internal
+// instance of a block chain. It is safe for concurrent access.
+func (b *blockManager) FetchTransactionStore(tx *btcutil.Tx) (blockchain.TxStore, error) {
+	reply := make(chan fetchTransactionStoreResponse, 1)
+	b.msgChan <- fetchTransactionStoreMsg{tx: tx, reply: reply}
+	response := <-reply
+	return response.TxStore, response.err
+}
+
 // ProcessBlock makes use of ProcessBlock on an internal instance of a block
 // chain.  It is funneled through the block manager since btcchain is not safe
 // for concurrent access.
diff --git a/mining.go b/mining.go
index 13edafe6..7af39cbd 100644
--- a/mining.go
+++ b/mining.go
@@ -369,7 +369,6 @@ func NewBlockTemplate(mempool *txMemPool, payToAddress btcutil.Address) (*BlockT
 	blockManager := mempool.server.blockManager
 	timeSource := mempool.server.timeSource
 	chainState := &blockManager.chainState
-	chain := blockManager.blockChain
 
 	// Extend the most recently known best block.
 	chainState.Lock()
@@ -458,7 +457,7 @@ mempoolLoop:
 		// inputs from the mempool since a transaction which depends on
 		// other transactions in the mempool must come after those
 		// dependencies in the final generated block.
-		txStore, err := chain.FetchTransactionStore(tx)
+		txStore, err := blockManager.FetchTransactionStore(tx)
 		if err != nil {
 			minrLog.Warnf("Unable to fetch transaction store for "+
 				"tx %s: %v", tx.Sha(), err)