@@ -126,14 +126,9 @@ namespace {
126
126
127
127
} // anon namespace
128
128
129
- // Bloom filter to limit respend relays to one
129
+ // Forward reference functions defined here:
130
130
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);
137
132
138
133
// ////////////////////////////////////////////////////////////////////////////
139
134
//
@@ -157,10 +152,24 @@ struct CMainSignals {
157
152
boost::signals2::signal<void (const uint256 &)> Inventory;
158
153
// Tells listeners to broadcast their data.
159
154
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;
160
161
} g_signals;
161
162
162
163
} // anon namespace
163
164
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
+
164
173
165
174
void RegisterWallet (CWalletInterface* pwalletIn) {
166
175
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
897
906
return false ;
898
907
}
899
908
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
-
939
909
bool AcceptToMemoryPool (CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree ,
940
910
bool * pfMissingInputs, bool fRejectInsaneFee )
941
911
{
@@ -973,7 +943,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
973
943
// Does tx conflict with a member of the pool, and is it not equivalent to that member?
974
944
if (pool.mapNextTx .count (outpoint) && !tx.IsEquivalentTo (*pool.mapNextTx [outpoint].ptx ))
975
945
{
976
- relayableRespend = RelayableRespend (outpoint, tx, false , doubleSpendFilter );
946
+ relayableRespend = g_signals. DetectedDoubleSpend (outpoint, tx, false );
977
947
if (!relayableRespend)
978
948
return false ;
979
949
}
@@ -1085,6 +1055,45 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
1085
1055
return !relayableRespend;
1086
1056
}
1087
1057
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
+
1088
1097
1089
1098
int CMerkleTx::GetDepthInMainChainINTERNAL (CBlockIndex* &pindexRet) const
1090
1099
{
0 commit comments