Skip to content
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

Merged
merged 2 commits into from Aug 1, 2018

Conversation

dnldd
Copy link
Member

@dnldd dnldd commented May 14, 2018

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:

  • 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.

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
@davecgh davecgh added this to the 1.3.0 milestone May 14, 2018
Copy link
Member

@davecgh davecgh left a 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.

@dnldd dnldd force-pushed the merge_mempool_orphan_outpoint branch 4 times, most recently from 4f8f72e to 6ab2609 Compare July 9, 2018 17:01
make(map[chainhash.Hash]*dcrutil.Tx)
log.Infof("added orphans by pre entry for %v", txIn.PreviousOutPoint)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like leftover debug.


// Remove any orphans that redeem outputs from this one if requested.
if removeRedeemers {
prevOut := wire.OutPoint{Hash: *txHash}
Copy link
Member

@davecgh davecgh Jul 27, 2018

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.

@dnldd dnldd force-pushed the merge_mempool_orphan_outpoint branch from 871e445 to fb05050 Compare July 28, 2018 17:35
}

for txOutIdx := range tx.MsgTx().TxOut {
prevOut := wire.OutPoint{Hash: *txHash,
Copy link
Member

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)
			}
		}

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}
Copy link
Member

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.

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(),
Copy link
Member

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.

@@ -14,6 +15,12 @@ import (
"testing"
"time"

"github.com/decred/dcrd/chaincfg/chainec"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra blank line

"github.com/decred/dcrd/blockchain/chaingen"
"github.com/decred/dcrd/blockchain/stake"
"github.com/decred/dcrd/dcrec"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra blank line

t.Fatalf("ProcessTransaction: failed to accept valid "+
"transaction %v", err)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra blank line.

t.Fatalf("ProcessTransaction: failed to accept orphan "+
"transaction %v", err)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra blank line.

// utxos can now be found.
_, err = harness.txPool.ProcessTransaction(revocation, false, false, true)
if err != nil {
t.Fatalf("ProcessTransaction: failed to accept orphan "+
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapping.


// Generate fake mined utxos for the regular transaction and the
// ticket created.
harness.AddFakeUTXO(tx, int64(tx.MsgTx().TxIn[0].BlockHeight))
Copy link
Member

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.

func (p *poolHarness) CreateVote(ticket *dcrutil.Tx) (*dcrutil.Tx, error) {
// Calculate the vote subsidy
subsidy := blockchain.CalcStakeVoteSubsidy(p.txPool.cfg.SubsidyCache,
p.chain.BestHeight(),
Copy link
Member

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.

@dnldd dnldd force-pushed the merge_mempool_orphan_outpoint branch 2 times, most recently from a8182a0 to 0cfd713 Compare August 1, 2018 14:33
@dnldd dnldd force-pushed the merge_mempool_orphan_outpoint branch from 0cfd713 to e321244 Compare August 1, 2018 17:33
Copy link
Member

@davecgh davecgh left a 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.

@dnldd dnldd force-pushed the merge_mempool_orphan_outpoint branch 3 times, most recently from f7fbb59 to a21705a Compare August 1, 2018 18:11
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.
@dnldd dnldd force-pushed the merge_mempool_orphan_outpoint branch from a21705a to e488d41 Compare August 1, 2018 18:57
@davecgh davecgh merged commit e488d41 into decred:master Aug 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants