New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mempool: Stricter orphan evaluation and eviction. #1207
Conversation
This modifies the way orphan removal and processing is done to more aggressively remove orphans that can no longer be valid due to other transactions being added or removed from the primary transaction pool. The net effect of these changes is that orphan pool will typically be much smaller which greatly improves its effectiveness. Previously, it would typically quickly reach the max allowed worst-case usage and effectively stay there forever. The following is a summary of the changes: - Modify the map that tracks which orphans redeem a given transaction to instead track by the specific outpoints that are redeemed - Modify the various orphan removal and processing functions to accept the full transaction rather than just its hash - Introduce a new flag on removeOrphans which specifies whether or not to remove the transactions that redeem the orphan being removed as well which is necessary since only some paths require it - Add a new function named removeOrphanDoubleSpends that is invoked whenever a transaction is added to the main pool and thus the outputs they spent become concrete spends - Introduce a new flag on maybeAcceptTransaction which specifies whether or not duplicate orphans should be rejected since only some paths require it - Modify processOrphans as follows: - Make use of the modified map - Use newly available flags and logic work more strictly work with tx chains - Recursively remove any orphans that also redeem any outputs redeemed by the accepted transactions - Several new tests to ensure proper functionality - Removing an orphan that doesn't exist is removed both when there is another orphan that redeems it and when there is not - Removing orphans works properly with orphan chains per the new remove redeemers flag - Removal of multi-input orphans that double spend an output when a concrete redeemer enters the transaction pool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several cases where this is incorrect in terms of the tree. It is creating prevOut
without regard to the appropriate tree which means it will not properly detect stake transactions. Tests for stake transactions need to be added as well to prove correctness.
4f8f72e
to
6ab2609
Compare
mempool/mempool.go
Outdated
make(map[chainhash.Hash]*dcrutil.Tx) | ||
log.Infof("added orphans by pre entry for %v", txIn.PreviousOutPoint) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like leftover debug.
mempool/mempool.go
Outdated
|
||
// Remove any orphans that redeem outputs from this one if requested. | ||
if removeRedeemers { | ||
prevOut := wire.OutPoint{Hash: *txHash} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section is not correct for Decred since it ignores the Tree
. It will miss stake transactions which have a Tree
of wire.TxTreeStake
.
871e445
to
fb05050
Compare
mempool/mempool.go
Outdated
} | ||
|
||
for txOutIdx := range tx.MsgTx().TxOut { | ||
prevOut := wire.OutPoint{Hash: *txHash, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be outside of the loop. No need to create another struct each iteration, just update the index.
prevOut := wire.OutPoint{Hash: *txHash, Tree: tree}
for txOutIdx := range tx.MsgTx().TxOut {
prevOut.Index = uint32(txOutIdx)
for _, orphan := range mp.orphansByPrev[prevOut] {
mp.removeOrphan(orphan, true)
}
}
mempool/mempool.go
Outdated
if txRedeemer, exists := mp.outpoints[*outpoint]; exists { | ||
|
||
for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ { | ||
prevOut := wire.OutPoint{Hash: *txHash, Index: i, Tree: tree} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here regarding the outpoint outside of the loop.
mempool/mempool.go
Outdated
log.Debugf("Unable to move orphan transaction "+ | ||
"%v to mempool: %v", tx.Hash(), err) | ||
// Skip to the next available output if there are none. | ||
prevOut := wire.OutPoint{Hash: *processItem.Hash(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. prevOut
should be outside the loop without Index
specified and set .Index
inside the loop.
mempool/mempool_test.go
Outdated
@@ -14,6 +15,12 @@ import ( | |||
"testing" | |||
"time" | |||
|
|||
"github.com/decred/dcrd/chaincfg/chainec" | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra blank line
mempool/mempool_test.go
Outdated
"github.com/decred/dcrd/blockchain/chaingen" | ||
"github.com/decred/dcrd/blockchain/stake" | ||
"github.com/decred/dcrd/dcrec" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra blank line
mempool/mempool_test.go
Outdated
t.Fatalf("ProcessTransaction: failed to accept valid "+ | ||
"transaction %v", err) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra blank line.
mempool/mempool_test.go
Outdated
t.Fatalf("ProcessTransaction: failed to accept orphan "+ | ||
"transaction %v", err) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra blank line.
mempool/mempool_test.go
Outdated
// utxos can now be found. | ||
_, err = harness.txPool.ProcessTransaction(revocation, false, false, true) | ||
if err != nil { | ||
t.Fatalf("ProcessTransaction: failed to accept orphan "+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrapping.
mempool/mempool_test.go
Outdated
|
||
// Generate fake mined utxos for the regular transaction and the | ||
// ticket created. | ||
harness.AddFakeUTXO(tx, int64(tx.MsgTx().TxIn[0].BlockHeight)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't needed. Only the ticket below.
mempool/mempool_test.go
Outdated
func (p *poolHarness) CreateVote(ticket *dcrutil.Tx) (*dcrutil.Tx, error) { | ||
// Calculate the vote subsidy | ||
subsidy := blockchain.CalcStakeVoteSubsidy(p.txPool.cfg.SubsidyCache, | ||
p.chain.BestHeight(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other param should be on the same line.
a8182a0
to
0cfd713
Compare
0cfd713
to
e321244
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code all looks correct now, but the recent update lost the upstream merge.
f7fbb59
to
a21705a
Compare
This modifies the way orphan removal and processing is done to more aggressively remove orphans that can no longer be valid due to other transactions being added or removed from the primary transaction pool. The net effect of these changes is that orphan pool will typically be much smaller which greatly improves its effectiveness. Previously, it would typically quickly reach the max allowed worst-case usage and effectively stay there forever. The following is a summary of the changes: - Modify the map that tracks which orphans redeem a given transaction to instead track by the specific outpoints that are redeemed - Modify the various orphan removal and processing functions to accept the full transaction rather than just its hash - Introduce a new flag on removeOrphans which specifies whether or not to remove the transactions that redeem the orphan being removed as well which is necessary since only some paths require it - Add a new function named removeOrphanDoubleSpends that is invoked whenever a transaction is added to the main pool and thus the outputs they spent become concrete spends - Introduce a new flag on maybeAcceptTransaction which specifies whether or not duplicate orphans should be rejected since only some paths require it - Modify processOrphans as follows: - Make use of the modified map - Use newly available flags and logic work more strictly work with tx chains - Recursively remove any orphans that also redeem any outputs redeemed by the accepted transactions - Several new tests to ensure proper functionality - Removing an orphan that doesn't exist is removed both when there is another orphan that redeems it and when there is not - Removing orphans works properly with orphan chains per the new remove redeemers flag - Removal of multi-input orphans that double spend an output when a concrete redeemer enters the transaction pool Ticket purchase, vote and revocation orphan tests have also been added.
a21705a
to
e488d41
Compare
This PR contains the following upstream commits:
This modifies the way orphan removal and processing is done to more
aggressively remove orphans that can no longer be valid due to other
transactions being added or removed from the primary transaction pool.
The net effect of these changes is that orphan pool will typically be
much smaller which greatly improves its effectiveness. Previously, it
would typically quickly reach the max allowed worst-case usage and
effectively stay there forever.
The following is a summary of the changes:
instead track by the specific outpoints that are redeemed
the full transaction rather than just its hash
to remove the transactions that redeem the orphan being removed as
well which is necessary since only some paths require it
whenever a transaction is added to the main pool and thus the outputs
they spent become concrete spends
or not duplicate orphans should be rejected since only some paths
require it
chains
by the accepted transactions
another orphan that redeems it and when there is not
remove redeemers flag
concrete redeemer enters the transaction pool
Ticket purchase, vote and revocation orphan tests have also been added.