@ -38,6 +38,11 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
assert ( inChainInputValue < = nValueIn ) ;
assert ( inChainInputValue < = nValueIn ) ;
feeDelta = 0 ;
feeDelta = 0 ;
nCountWithAncestors = 1 ;
nSizeWithAncestors = nTxSize ;
nModFeesWithAncestors = nFee ;
nSigOpCountWithAncestors = sigOpCount ;
}
}
CTxMemPoolEntry : : CTxMemPoolEntry ( const CTxMemPoolEntry & other )
CTxMemPoolEntry : : CTxMemPoolEntry ( const CTxMemPoolEntry & other )
@ -58,6 +63,7 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
void CTxMemPoolEntry : : UpdateFeeDelta ( int64_t newFeeDelta )
void CTxMemPoolEntry : : UpdateFeeDelta ( int64_t newFeeDelta )
{
{
nModFeesWithDescendants + = newFeeDelta - feeDelta ;
nModFeesWithDescendants + = newFeeDelta - feeDelta ;
nModFeesWithAncestors + = newFeeDelta - feeDelta ;
feeDelta = newFeeDelta ;
feeDelta = newFeeDelta ;
}
}
@ -99,6 +105,8 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
modifyFee + = cit - > GetModifiedFee ( ) ;
modifyFee + = cit - > GetModifiedFee ( ) ;
modifyCount + + ;
modifyCount + + ;
cachedDescendants [ updateIt ] . insert ( cit ) ;
cachedDescendants [ updateIt ] . insert ( cit ) ;
// Update ancestor state for each descendant
mapTx . modify ( cit , update_ancestor_state ( updateIt - > GetTxSize ( ) , updateIt - > GetModifiedFee ( ) , 1 , updateIt - > GetSigOpCount ( ) ) ) ;
}
}
}
}
mapTx . modify ( updateIt , update_descendant_state ( modifySize , modifyFee , modifyCount ) ) ;
mapTx . modify ( updateIt , update_descendant_state ( modifySize , modifyFee , modifyCount ) ) ;
@ -108,6 +116,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
// which has been re-added to the mempool.
// which has been re-added to the mempool.
// for each entry, look for descendants that are outside hashesToUpdate, and
// for each entry, look for descendants that are outside hashesToUpdate, and
// add fee/size information for such descendants to the parent.
// add fee/size information for such descendants to the parent.
// for each such descendant, also update the ancestor state to include the parent.
void CTxMemPool : : UpdateTransactionsFromBlock ( const std : : vector < uint256 > & vHashesToUpdate )
void CTxMemPool : : UpdateTransactionsFromBlock ( const std : : vector < uint256 > & vHashesToUpdate )
{
{
LOCK ( cs ) ;
LOCK ( cs ) ;
@ -228,6 +237,20 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
}
}
}
}
void CTxMemPool : : UpdateEntryForAncestors ( txiter it , const setEntries & setAncestors )
{
int64_t updateCount = setAncestors . size ( ) ;
int64_t updateSize = 0 ;
CAmount updateFee = 0 ;
int updateSigOps = 0 ;
BOOST_FOREACH ( txiter ancestorIt , setAncestors ) {
updateSize + = ancestorIt - > GetTxSize ( ) ;
updateFee + = ancestorIt - > GetModifiedFee ( ) ;
updateSigOps + = ancestorIt - > GetSigOpCount ( ) ;
}
mapTx . modify ( it , update_ancestor_state ( updateSize , updateFee , updateCount , updateSigOps ) ) ;
}
void CTxMemPool : : UpdateChildrenForRemoval ( txiter it )
void CTxMemPool : : UpdateChildrenForRemoval ( txiter it )
{
{
const setEntries & setMemPoolChildren = GetMemPoolChildren ( it ) ;
const setEntries & setMemPoolChildren = GetMemPoolChildren ( it ) ;
@ -236,11 +259,30 @@ void CTxMemPool::UpdateChildrenForRemoval(txiter it)
}
}
}
}
void CTxMemPool : : UpdateForRemoveFromMempool ( const setEntries & entriesToRemove )
void CTxMemPool : : UpdateForRemoveFromMempool ( const setEntries & entriesToRemove , bool updateDescendants )
{
{
// For each entry, walk back all ancestors and decrement size associated with this
// For each entry, walk back all ancestors and decrement size associated with this
// transaction
// transaction
const uint64_t nNoLimit = std : : numeric_limits < uint64_t > : : max ( ) ;
const uint64_t nNoLimit = std : : numeric_limits < uint64_t > : : max ( ) ;
if ( updateDescendants ) {
// updateDescendants should be true whenever we're not recursively
// removing a tx and all its descendants, eg when a transaction is
// confirmed in a block.
// Here we only update statistics and not data in mapLinks (which
// we need to preserve until we're finished with all operations that
// need to traverse the mempool).
BOOST_FOREACH ( txiter removeIt , entriesToRemove ) {
setEntries setDescendants ;
CalculateDescendants ( removeIt , setDescendants ) ;
setDescendants . erase ( removeIt ) ; // don't update state for self
int64_t modifySize = - ( ( int64_t ) removeIt - > GetTxSize ( ) ) ;
CAmount modifyFee = - removeIt - > GetModifiedFee ( ) ;
int modifySigOps = - removeIt - > GetSigOpCount ( ) ;
BOOST_FOREACH ( txiter dit , setDescendants ) {
mapTx . modify ( dit , update_ancestor_state ( modifySize , modifyFee , - 1 , modifySigOps ) ) ;
}
}
}
BOOST_FOREACH ( txiter removeIt , entriesToRemove ) {
BOOST_FOREACH ( txiter removeIt , entriesToRemove ) {
setEntries setAncestors ;
setEntries setAncestors ;
const CTxMemPoolEntry & entry = * removeIt ;
const CTxMemPoolEntry & entry = * removeIt ;
@ -264,10 +306,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
// transactions as the set of things to update for removal.
// transactions as the set of things to update for removal.
CalculateMemPoolAncestors ( entry , setAncestors , nNoLimit , nNoLimit , nNoLimit , nNoLimit , dummy , false ) ;
CalculateMemPoolAncestors ( entry , setAncestors , nNoLimit , nNoLimit , nNoLimit , nNoLimit , dummy , false ) ;
// Note that UpdateAncestorsOf severs the child links that point to
// Note that UpdateAncestorsOf severs the child links that point to
// removeIt in the entries for the parents of removeIt. This is
// removeIt in the entries for the parents of removeIt.
// fine since we don't need to use the mempool children of any entries
// to walk back over our ancestors (but we do need the mempool
// parents!)
UpdateAncestorsOf ( false , removeIt , setAncestors ) ;
UpdateAncestorsOf ( false , removeIt , setAncestors ) ;
}
}
// After updating all the ancestor sizes, we can now sever the link between each
// After updating all the ancestor sizes, we can now sever the link between each
@ -278,7 +317,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
}
}
}
}
void CTxMemPoolEntry : : UpdateState ( int64_t modifySize , CAmount modifyFee , int64_t modifyCount )
void CTxMemPoolEntry : : UpdateDescendant State ( int64_t modifySize , CAmount modifyFee , int64_t modifyCount )
{
{
nSizeWithDescendants + = modifySize ;
nSizeWithDescendants + = modifySize ;
assert ( int64_t ( nSizeWithDescendants ) > 0 ) ;
assert ( int64_t ( nSizeWithDescendants ) > 0 ) ;
@ -287,6 +326,17 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t
assert ( int64_t ( nCountWithDescendants ) > 0 ) ;
assert ( int64_t ( nCountWithDescendants ) > 0 ) ;
}
}
void CTxMemPoolEntry : : UpdateAncestorState ( int64_t modifySize , CAmount modifyFee , int64_t modifyCount , int modifySigOps )
{
nSizeWithAncestors + = modifySize ;
assert ( int64_t ( nSizeWithAncestors ) > 0 ) ;
nModFeesWithAncestors + = modifyFee ;
nCountWithAncestors + = modifyCount ;
assert ( int64_t ( nCountWithAncestors ) > 0 ) ;
nSigOpCountWithAncestors + = modifySigOps ;
assert ( int ( nSigOpCountWithAncestors ) > = 0 ) ;
}
CTxMemPool : : CTxMemPool ( const CFeeRate & _minReasonableRelayFee ) :
CTxMemPool : : CTxMemPool ( const CFeeRate & _minReasonableRelayFee ) :
nTransactionsUpdated ( 0 )
nTransactionsUpdated ( 0 )
{
{
@ -377,6 +427,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
}
}
}
}
UpdateAncestorsOf ( true , newit , setAncestors ) ;
UpdateAncestorsOf ( true , newit , setAncestors ) ;
UpdateEntryForAncestors ( newit , setAncestors ) ;
nTransactionsUpdated + + ;
nTransactionsUpdated + + ;
totalTxSize + = entry . GetTxSize ( ) ;
totalTxSize + = entry . GetTxSize ( ) ;
@ -459,7 +510,7 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, std::list<CTransact
BOOST_FOREACH ( txiter it , setAllRemoves ) {
BOOST_FOREACH ( txiter it , setAllRemoves ) {
removed . push_back ( it - > GetTx ( ) ) ;
removed . push_back ( it - > GetTx ( ) ) ;
}
}
RemoveStaged ( setAllRemoves ) ;
RemoveStaged ( setAllRemoves , false ) ;
}
}
}
}
@ -532,7 +583,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned i
if ( it ! = mapTx . end ( ) ) {
if ( it ! = mapTx . end ( ) ) {
setEntries stage ;
setEntries stage ;
stage . insert ( it ) ;
stage . insert ( it ) ;
RemoveStaged ( stage ) ;
RemoveStaged ( stage , true ) ;
}
}
removeConflicts ( tx , conflicts ) ;
removeConflicts ( tx , conflicts ) ;
ClearPrioritisation ( tx . GetHash ( ) ) ;
ClearPrioritisation ( tx . GetHash ( ) ) ;
@ -590,6 +641,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
innerUsage + = memusage : : DynamicUsage ( links . parents ) + memusage : : DynamicUsage ( links . children ) ;
innerUsage + = memusage : : DynamicUsage ( links . parents ) + memusage : : DynamicUsage ( links . children ) ;
bool fDependsWait = false ;
bool fDependsWait = false ;
setEntries setParentCheck ;
setEntries setParentCheck ;
int64_t parentSizes = 0 ;
unsigned int parentSigOpCount = 0 ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin ) {
BOOST_FOREACH ( const CTxIn & txin , tx . vin ) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
indexed_transaction_set : : const_iterator it2 = mapTx . find ( txin . prevout . hash ) ;
indexed_transaction_set : : const_iterator it2 = mapTx . find ( txin . prevout . hash ) ;
@ -597,7 +650,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
const CTransaction & tx2 = it2 - > GetTx ( ) ;
const CTransaction & tx2 = it2 - > GetTx ( ) ;
assert ( tx2 . vout . size ( ) > txin . prevout . n & & ! tx2 . vout [ txin . prevout . n ] . IsNull ( ) ) ;
assert ( tx2 . vout . size ( ) > txin . prevout . n & & ! tx2 . vout [ txin . prevout . n ] . IsNull ( ) ) ;
fDependsWait = true ;
fDependsWait = true ;
setParentCheck . insert ( it2 ) ;
if ( setParentCheck . insert ( it2 ) . second ) {
parentSizes + = it2 - > GetTxSize ( ) ;
parentSigOpCount + = it2 - > GetSigOpCount ( ) ;
}
} else {
} else {
const CCoins * coins = pcoins - > AccessCoins ( txin . prevout . hash ) ;
const CCoins * coins = pcoins - > AccessCoins ( txin . prevout . hash ) ;
assert ( coins & & coins - > IsAvailable ( txin . prevout . n ) ) ;
assert ( coins & & coins - > IsAvailable ( txin . prevout . n ) ) ;
@ -610,17 +666,19 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
i + + ;
i + + ;
}
}
assert ( setParentCheck = = GetMemPoolParents ( it ) ) ;
assert ( setParentCheck = = GetMemPoolParents ( it ) ) ;
// Also check to make sure ancestor size/sigops are >= sum with immediate
// parents.
assert ( it - > GetSizeWithAncestors ( ) > = parentSizes + it - > GetTxSize ( ) ) ;
assert ( it - > GetSigOpCountWithAncestors ( ) > = parentSigOpCount + it - > GetSigOpCount ( ) ) ;
// Check children against mapNextTx
// Check children against mapNextTx
CTxMemPool : : setEntries setChildrenCheck ;
CTxMemPool : : setEntries setChildrenCheck ;
std : : map < COutPoint , CInPoint > : : const_iterator iter = mapNextTx . lower_bound ( COutPoint ( it - > GetTx ( ) . GetHash ( ) , 0 ) ) ;
std : : map < COutPoint , CInPoint > : : const_iterator iter = mapNextTx . lower_bound ( COutPoint ( it - > GetTx ( ) . GetHash ( ) , 0 ) ) ;
int64_t childSizes = 0 ;
int64_t childSizes = 0 ;
CAmount childModFee = 0 ;
for ( ; iter ! = mapNextTx . end ( ) & & iter - > first . hash = = it - > GetTx ( ) . GetHash ( ) ; + + iter ) {
for ( ; iter ! = mapNextTx . end ( ) & & iter - > first . hash = = it - > GetTx ( ) . GetHash ( ) ; + + iter ) {
txiter childit = mapTx . find ( iter - > second . ptx - > GetHash ( ) ) ;
txiter childit = mapTx . find ( iter - > second . ptx - > GetHash ( ) ) ;
assert ( childit ! = mapTx . end ( ) ) ; // mapNextTx points to in-mempool transactions
assert ( childit ! = mapTx . end ( ) ) ; // mapNextTx points to in-mempool transactions
if ( setChildrenCheck . insert ( childit ) . second ) {
if ( setChildrenCheck . insert ( childit ) . second ) {
childSizes + = childit - > GetTxSize ( ) ;
childSizes + = childit - > GetTxSize ( ) ;
childModFee + = childit - > GetModifiedFee ( ) ;
}
}
}
}
assert ( setChildrenCheck = = GetMemPoolChildren ( it ) ) ;
assert ( setChildrenCheck = = GetMemPoolChildren ( it ) ) ;
@ -812,9 +870,9 @@ size_t CTxMemPool::DynamicMemoryUsage() const {
return memusage : : MallocUsage ( sizeof ( CTxMemPoolEntry ) + 12 * sizeof ( void * ) ) * mapTx . size ( ) + memusage : : DynamicUsage ( mapNextTx ) + memusage : : DynamicUsage ( mapDeltas ) + memusage : : DynamicUsage ( mapLinks ) + cachedInnerUsage ;
return memusage : : MallocUsage ( sizeof ( CTxMemPoolEntry ) + 12 * sizeof ( void * ) ) * mapTx . size ( ) + memusage : : DynamicUsage ( mapNextTx ) + memusage : : DynamicUsage ( mapDeltas ) + memusage : : DynamicUsage ( mapLinks ) + cachedInnerUsage ;
}
}
void CTxMemPool : : RemoveStaged ( setEntries & stage ) {
void CTxMemPool : : RemoveStaged ( setEntries & stage , bool updateDescendants ) {
AssertLockHeld ( cs ) ;
AssertLockHeld ( cs ) ;
UpdateForRemoveFromMempool ( stage ) ;
UpdateForRemoveFromMempool ( stage , updateDescendants ) ;
BOOST_FOREACH ( const txiter & it , stage ) {
BOOST_FOREACH ( const txiter & it , stage ) {
removeUnchecked ( it ) ;
removeUnchecked ( it ) ;
}
}
@ -832,7 +890,7 @@ int CTxMemPool::Expire(int64_t time) {
BOOST_FOREACH ( txiter removeit , toremove ) {
BOOST_FOREACH ( txiter removeit , toremove ) {
CalculateDescendants ( removeit , stage ) ;
CalculateDescendants ( removeit , stage ) ;
}
}
RemoveStaged ( stage ) ;
RemoveStaged ( stage , false ) ;
return stage . size ( ) ;
return stage . size ( ) ;
}
}
@ -941,7 +999,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
BOOST_FOREACH ( txiter it , stage )
BOOST_FOREACH ( txiter it , stage )
txn . push_back ( it - > GetTx ( ) ) ;
txn . push_back ( it - > GetTx ( ) ) ;
}
}
RemoveStaged ( stage ) ;
RemoveStaged ( stage , false ) ;
if ( pvNoSpendsRemaining ) {
if ( pvNoSpendsRemaining ) {
BOOST_FOREACH ( const CTransaction & tx , txn ) {
BOOST_FOREACH ( const CTransaction & tx , txn ) {
BOOST_FOREACH ( const CTxIn & txin , tx . vin ) {
BOOST_FOREACH ( const CTxIn & txin , tx . vin ) {