From 1f2ae2f78ff755e1ff6610b692ed48e85ea2eb63 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 1 Mar 2018 20:53:49 -0600 Subject: [PATCH] mining: Fix duplicate txns in the prio heap. This prevents the ability for duplicate transactions to be added to the mining priority heap when a transaction spends multiple outputs from the same input transaction by converting the dependency tracking to use a map keyed by the transaction hash instead of a linked list. --- mining.go | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/mining.go b/mining.go index aa8ca10f4b..7569748741 100644 --- a/mining.go +++ b/mining.go @@ -7,7 +7,6 @@ package main import ( "container/heap" - "container/list" "encoding/binary" "fmt" "math" @@ -659,13 +658,12 @@ func spendTransaction(utxoView *blockchain.UtxoViewpoint, tx *dcrutil.Tx, // logSkippedDeps logs any dependencies which are also skipped as a result of // skipping a transaction while generating a block template at the trace level. -func logSkippedDeps(tx *dcrutil.Tx, deps *list.List) { +func logSkippedDeps(tx *dcrutil.Tx, deps map[chainhash.Hash]*txPrioItem) { if deps == nil { return } - for e := deps.Front(); e != nil; e = e.Next() { - item := e.Value.(*txPrioItem) + for _, item := range deps { minrLog.Tracef("Skipping tx %s since it depends on %s\n", item.tx.Hash(), tx.Hash()) } @@ -1265,7 +1263,7 @@ func NewBlockTemplate(policy *mining.Policy, server *server, // dependsOn map kept with each dependent transaction helps quickly // determine which dependent transactions are now eligible for inclusion // in the block once each transaction has been included. - dependers := make(map[chainhash.Hash]*list.List) + dependers := make(map[chainhash.Hash]map[chainhash.Hash]*txPrioItem) // Create slices to hold the fees and number of signature operations // for each of the selected transactions and add an entry for the @@ -1351,12 +1349,12 @@ mempoolLoop: // The transaction is referencing another // transaction in the source pool, so setup an // ordering dependency. - depList, exists := dependers[*originHash] + deps, exists := dependers[*originHash] if !exists { - depList = list.New() - dependers[*originHash] = depList + deps = make(map[chainhash.Hash]*txPrioItem) + dependers[*originHash] = deps } - depList.PushBack(prioItem) + deps[*prioItem.tx.Hash()] = prioItem if prioItem.dependsOn == nil { prioItem.dependsOn = make( map[chainhash.Hash]struct{}) @@ -1632,16 +1630,12 @@ mempoolLoop: // Add transactions which depend on this one (and also do not // have any other unsatisified dependencies) to the priority // queue. - if deps != nil { - for e := deps.Front(); e != nil; e = e.Next() { - // Add the transaction to the priority queue if - // there are no more dependencies after this - // one. - item := e.Value.(*txPrioItem) - delete(item.dependsOn, *tx.Hash()) - if len(item.dependsOn) == 0 { - heap.Push(priorityQueue, item) - } + for _, item := range deps { + // Add the transaction to the priority queue if there + // are no more dependencies after this one. + delete(item.dependsOn, *tx.Hash()) + if len(item.dependsOn) == 0 { + heap.Push(priorityQueue, item) } } }