@ -157,6 +157,39 @@ namespace {
@@ -157,6 +157,39 @@ namespace {
set < int > setDirtyFileInfo ;
} // anon namespace
/* Use this class to start tracking transactions that are removed from the
* mempool and pass all those transactions through SyncTransaction when the
* object goes out of scope . This is currently only used to call SyncTransaction
* on conflicts removed from the mempool during block connection . Applied in
* ActivateBestChain around ActivateBestStep which in turn calls :
* ConnectTip - > removeForBlock - > removeConflicts
*/
class MemPoolConflictRemovalTracker
{
private :
std : : vector < CTransactionRef > conflictedTxs ;
CTxMemPool & pool ;
public :
MemPoolConflictRemovalTracker ( CTxMemPool & _pool ) : pool ( _pool ) {
pool . NotifyEntryRemoved . connect ( boost : : bind ( & MemPoolConflictRemovalTracker : : NotifyEntryRemoved , this , _1 , _2 ) ) ;
}
void NotifyEntryRemoved ( CTransactionRef txRemoved , MemPoolRemovalReason reason ) {
if ( reason = = MemPoolRemovalReason : : CONFLICT ) {
conflictedTxs . push_back ( txRemoved ) ;
}
}
~ MemPoolConflictRemovalTracker ( ) {
pool . NotifyEntryRemoved . disconnect ( boost : : bind ( & MemPoolConflictRemovalTracker : : NotifyEntryRemoved , this , _1 , _2 ) ) ;
for ( const auto & tx : conflictedTxs ) {
GetMainSignals ( ) . SyncTransaction ( * tx , NULL , CMainSignals : : SYNC_TRANSACTION_NOT_IN_BLOCK ) ;
}
conflictedTxs . clear ( ) ;
}
} ;
CBlockIndex * FindForkInGlobalIndex ( const CChain & chain , const CBlockLocator & locator )
{
// Find the first block the caller has in the main chain
@ -956,7 +989,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
@@ -956,7 +989,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if ( plTxnReplaced )
plTxnReplaced - > push_back ( it - > GetSharedTx ( ) ) ;
}
pool . RemoveStaged ( allConflicting , false ) ;
pool . RemoveStaged ( allConflicting , false , MemPoolRemovalReason : : REPLACED ) ;
// This transaction should only count for fee estimation if
// the node is not behind and it is not dependent on any other
@ -2166,7 +2199,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
@@ -2166,7 +2199,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
// ignore validation errors in resurrected transactions
CValidationState stateDummy ;
if ( tx . IsCoinBase ( ) | | ! AcceptToMemoryPool ( mempool , stateDummy , it , false , NULL , NULL , true ) ) {
mempool . removeRecursive ( tx ) ;
mempool . removeRecursive ( tx , MemPoolRemovalReason : : REORG ) ;
} else if ( mempool . exists ( tx . GetHash ( ) ) ) {
vHashUpdate . push_back ( tx . GetHash ( ) ) ;
}
@ -2453,6 +2486,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
@@ -2453,6 +2486,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
bool fInitialDownload ;
{
LOCK ( cs_main ) ;
{ // TODO: Tempoarily ensure that mempool removals are notified before
// connected transactions. This shouldn't matter, but the abandoned
// state of transactions in our wallet is currently cleared when we
// receive another notification and there is a race condition where
// notification of a connected conflict might cause an outside process
// to abandon a transaction and then have it inadvertantly cleared by
// the notification that the conflicted transaction was evicted.
MemPoolConflictRemovalTracker mrt ( mempool ) ;
CBlockIndex * pindexOldTip = chainActive . Tip ( ) ;
if ( pindexMostWork = = NULL ) {
pindexMostWork = FindMostWorkChain ( ) ;
@ -2476,6 +2517,10 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
@@ -2476,6 +2517,10 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
fInitialDownload = IsInitialBlockDownload ( ) ;
// throw all transactions though the signal-interface
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
// Transactions in the connnected block are notified
for ( const auto & pair : connectTrace . blocksConnected ) {
assert ( pair . second ) ;
const CBlock & block = * ( pair . second ) ;
@ -3597,7 +3642,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
@@ -3597,7 +3642,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
return error ( " VerifyDB() : * * * ReadBlockFromDisk failed at % d , hash = % s " , pindex->nHeight, pindex->GetBlockHash().ToString()) ;
// check level 1: verify block validity
if ( nCheckLevel > = 1 & & ! CheckBlock ( block , state , chainparams . GetConsensus ( ) ) )
return error ( " %s: *** found bad block at %d, hash=%s (%s) \n " , __func__ ,
return error ( " %s: *** found bad block at %d, hash=%s (%s) \n " , __func__ ,
pindex - > nHeight , pindex - > GetBlockHash ( ) . ToString ( ) , FormatStateMessage ( state ) ) ;
// check level 2: verify undo validity
if ( nCheckLevel > = 2 & & pindex ) {
@ -3768,7 +3813,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
@@ -3768,7 +3813,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
return true ;
}
bool InitBlockIndex ( const CChainParams & chainparams )
bool InitBlockIndex ( const CChainParams & chainparams )
{
LOCK ( cs_main ) ;