@@ -125,9 +125,14 @@ namespace {
125
125
126
126
} // anon namespace
127
127
128
- // Forward reference functions defined here:
128
+ // Bloom filter to limit respend relays to one
129
129
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
+
131
136
132
137
// ////////////////////////////////////////////////////////////////////////////
133
138
//
@@ -151,24 +156,10 @@ struct CMainSignals {
151
156
boost::signals2::signal<void (const uint256 &)> Inventory;
152
157
// Tells listeners to broadcast their data.
153
158
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;
160
159
} g_signals;
161
160
162
161
} // anon namespace
163
162
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
-
172
163
173
164
void RegisterWallet (CWalletInterface* pwalletIn) {
174
165
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
908
899
return false ;
909
900
}
910
901
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
+
911
941
bool AcceptToMemoryPool (CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree ,
912
942
bool * pfMissingInputs, bool fRejectInsaneFee )
913
943
{
@@ -945,7 +975,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
945
975
// Does tx conflict with a member of the pool, and is it not equivalent to that member?
946
976
if (pool.mapNextTx .count (outpoint) && !tx.IsEquivalentTo (*pool.mapNextTx [outpoint].ptx ))
947
977
{
948
- relayableRespend = g_signals. DetectedDoubleSpend (outpoint, tx, false );
978
+ relayableRespend = RelayableRespend (outpoint, tx, false , doubleSpendFilter );
949
979
if (!relayableRespend)
950
980
return false ;
951
981
}
@@ -1057,45 +1087,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
1057
1087
return !relayableRespend;
1058
1088
}
1059
1089
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
-
1099
1090
1100
1091
int CMerkleTx::GetDepthInMainChainINTERNAL (CBlockIndex* &pindexRet) const
1101
1092
{
0 commit comments