Skip to content

Commit 0da6b3f

Browse files
committed
Remove signal DoubleSpendDetected, use function
Also removes the need for forward reference to RelayableRespend.
1 parent 88dd359 commit 0da6b3f

File tree

3 files changed

+50
-59
lines changed

3 files changed

+50
-59
lines changed

src/init.cpp

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

1179-
RegisterInternalSignals();
1179+
InitRespendFilter();
11801180
StartNode(threadGroup);
11811181
if (fServer)
11821182
StartRPCThreads();

src/main.cpp

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

126126
} // anon namespace
127127

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

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

162161
} // anon namespace
163162

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

173164
void RegisterWallet(CWalletInterface* pwalletIn) {
174165
g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
@@ -908,6 +899,45 @@ bool RateLimitExceeded(double& dCount, int64_t& nLastTime, int64_t nLimit, unsig
908899
return false;
909900
}
910901

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

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

11001091
int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const
11011092
{

src/main.h

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

109109
struct CBlockTemplate;
110110

111-
/** Set up internal signal handlers **/
112-
void RegisterInternalSignals();
111+
/** Initialize respend bloom filter **/
112+
void InitRespendFilter();
113113

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

0 commit comments

Comments
 (0)