Skip to content

Commit 67cc8f2

Browse files
committed
Revert "Remove signal DoubleSpendDetected, use function"
This reverts commit 0da6b3f.
1 parent 0de61e7 commit 67cc8f2

File tree

3 files changed

+59
-50
lines changed

3 files changed

+59
-50
lines changed

src/init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ bool AppInit2(boost::thread_group& threadGroup)
12291229
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
12301230
#endif
12311231

1232-
InitRespendFilter();
1232+
RegisterInternalSignals();
12331233
StartNode(threadGroup);
12341234
if (fServer)
12351235
StartRPCThreads();

src/main.cpp

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,9 @@ namespace {
126126

127127
} // anon namespace
128128

129-
// Bloom filter to limit respend relays to one
129+
// Forward reference functions defined here:
130130
static const unsigned int MAX_DOUBLESPEND_BLOOM = 1000;
131-
static CBloomFilter doubleSpendFilter;
132-
void InitRespendFilter() {
133-
seed_insecure_rand();
134-
doubleSpendFilter = CBloomFilter(MAX_DOUBLESPEND_BLOOM, 0.01, insecure_rand(), BLOOM_UPDATE_NONE);
135-
}
136-
131+
static bool RelayableRespend(const COutPoint& outPoint, const CTransaction& doubleSpend, bool fInBlock, CBloomFilter& filter);
137132

138133
//////////////////////////////////////////////////////////////////////////////
139134
//
@@ -157,10 +152,24 @@ struct CMainSignals {
157152
boost::signals2::signal<void (const uint256 &)> Inventory;
158153
// Tells listeners to broadcast their data.
159154
boost::signals2::signal<void ()> Broadcast;
155+
// Notifies listeners of detection of a double-spent transaction. Arguments are outpoint that is
156+
// double-spent, first transaction seen, double-spend transaction, and whether the second double-spend
157+
// transaction was first seen in a block.
158+
// Note: only notifies if the previous transaction is in the memory pool; if previous transction was in a block,
159+
// then the double-spend simply fails when we try to lookup the inputs in the current UTXO set.
160+
boost::signals2::signal<bool (const COutPoint&, const CTransaction&, bool)> DetectedDoubleSpend;
160161
} g_signals;
161162

162163
} // anon namespace
163164

165+
void RegisterInternalSignals() {
166+
static CBloomFilter doubleSpendFilter;
167+
seed_insecure_rand();
168+
doubleSpendFilter = CBloomFilter(MAX_DOUBLESPEND_BLOOM, 0.01, insecure_rand(), BLOOM_UPDATE_NONE);
169+
170+
g_signals.DetectedDoubleSpend.connect(boost::bind(RelayableRespend, _1, _2, _3, doubleSpendFilter));
171+
}
172+
164173

165174
void RegisterWallet(CWalletInterface* pwalletIn) {
166175
g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
@@ -897,45 +906,6 @@ bool RateLimitExceeded(double& dCount, int64_t& nLastTime, int64_t nLimit, unsig
897906
return false;
898907
}
899908

900-
static bool RelayableRespend(const COutPoint& outPoint, const CTransaction& doubleSpend, bool fInBlock, CBloomFilter& filter)
901-
{
902-
// Relaying double-spend attempts to our peers lets them detect when
903-
// somebody might be trying to cheat them. However, blindly relaying
904-
// every double-spend across the entire network gives attackers
905-
// a denial-of-service attack: just generate a stream of double-spends
906-
// re-spending the same (limited) set of outpoints owned by the attacker.
907-
// So, we use a bloom filter and only relay (at most) the first double
908-
// spend for each outpoint. False-positives ("we have already relayed")
909-
// are OK, because if the peer doesn't hear about the double-spend
910-
// from us they are very likely to hear about it from another peer, since
911-
// each peer uses a different, randomized bloom filter.
912-
913-
if (fInBlock || filter.contains(outPoint)) return false;
914-
915-
// Apply an independent rate limit to double-spend relays
916-
static double dRespendCount;
917-
static int64_t nLastRespendTime;
918-
static int64_t nRespendLimit = GetArg("-limitrespendrelay", 100);
919-
unsigned int nSize = ::GetSerializeSize(doubleSpend, SER_NETWORK, PROTOCOL_VERSION);
920-
921-
if (RateLimitExceeded(dRespendCount, nLastRespendTime, nRespendLimit, nSize))
922-
{
923-
LogPrint("mempool", "Double-spend relay rejected by rate limiter\n");
924-
return false;
925-
}
926-
927-
LogPrint("mempool", "Rate limit dRespendCount: %g => %g\n", dRespendCount, dRespendCount+nSize);
928-
929-
// Clear the filter on average every MAX_DOUBLE_SPEND_BLOOM
930-
// insertions
931-
if (insecure_rand()%MAX_DOUBLESPEND_BLOOM == 0)
932-
filter.clear();
933-
934-
filter.insert(outPoint);
935-
936-
return true;
937-
}
938-
939909
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
940910
bool* pfMissingInputs, bool fRejectInsaneFee)
941911
{
@@ -973,7 +943,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
973943
// Does tx conflict with a member of the pool, and is it not equivalent to that member?
974944
if (pool.mapNextTx.count(outpoint) && !tx.IsEquivalentTo(*pool.mapNextTx[outpoint].ptx))
975945
{
976-
relayableRespend = RelayableRespend(outpoint, tx, false, doubleSpendFilter);
946+
relayableRespend = g_signals.DetectedDoubleSpend(outpoint, tx, false);
977947
if (!relayableRespend)
978948
return false;
979949
}
@@ -1085,6 +1055,45 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
10851055
return !relayableRespend;
10861056
}
10871057

1058+
static bool RelayableRespend(const COutPoint& outPoint, const CTransaction& doubleSpend, bool fInBlock, CBloomFilter& filter)
1059+
{
1060+
// Relaying double-spend attempts to our peers lets them detect when
1061+
// somebody might be trying to cheat them. However, blindly relaying
1062+
// every double-spend across the entire network gives attackers
1063+
// a denial-of-service attack: just generate a stream of double-spends
1064+
// re-spending the same (limited) set of outpoints owned by the attacker.
1065+
// So, we use a bloom filter and only relay (at most) the first double
1066+
// spend for each outpoint. False-positives ("we have already relayed")
1067+
// are OK, because if the peer doesn't hear about the double-spend
1068+
// from us they are very likely to hear about it from another peer, since
1069+
// each peer uses a different, randomized bloom filter.
1070+
1071+
if (fInBlock || filter.contains(outPoint)) return false;
1072+
1073+
// Apply an independent rate limit to double-spend relays
1074+
static double dRespendCount;
1075+
static int64_t nLastRespendTime;
1076+
static int64_t nRespendLimit = GetArg("-limitrespendrelay", 100);
1077+
unsigned int nSize = ::GetSerializeSize(doubleSpend, SER_NETWORK, PROTOCOL_VERSION);
1078+
1079+
if (RateLimitExceeded(dRespendCount, nLastRespendTime, nRespendLimit, nSize))
1080+
{
1081+
LogPrint("mempool", "Double-spend relay rejected by rate limiter\n");
1082+
return false;
1083+
}
1084+
1085+
LogPrint("mempool", "Rate limit dRespendCount: %g => %g\n", dRespendCount, dRespendCount+nSize);
1086+
1087+
// Clear the filter on average every MAX_DOUBLE_SPEND_BLOOM
1088+
// insertions
1089+
if (insecure_rand()%MAX_DOUBLESPEND_BLOOM == 0)
1090+
filter.clear();
1091+
1092+
filter.insert(outPoint);
1093+
1094+
return true;
1095+
}
1096+
10881097

10891098
int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const
10901099
{

src/main.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ struct CNodeStateStats;
112112

113113
struct CBlockTemplate;
114114

115-
/** Initialize respend bloom filter **/
116-
void InitRespendFilter();
115+
/** Set up internal signal handlers **/
116+
void RegisterInternalSignals();
117117

118118
/** Register a wallet to receive updates from core */
119119
void RegisterWallet(CWalletInterface* pwalletIn);

0 commit comments

Comments
 (0)