7
7
8
8
#include " addrman.h"
9
9
#include " alert.h"
10
+ #include " bloom.h"
10
11
#include " chainparams.h"
11
12
#include " checkpoints.h"
12
13
#include " checkqueue.h"
@@ -124,6 +125,10 @@ namespace {
124
125
125
126
} // anon namespace
126
127
128
+ // Forward reference functions defined here:
129
+ static const unsigned int MAX_DOUBLESPEND_BLOOM = 1000 ;
130
+ static void RelayDoubleSpend (const COutPoint& outPoint, const CTransaction& doubleSpend, bool fInBlock , CBloomFilter& filter);
131
+
127
132
// ////////////////////////////////////////////////////////////////////////////
128
133
//
129
134
// dispatching functions
@@ -146,10 +151,25 @@ struct CMainSignals {
146
151
boost::signals2::signal<void (const uint256 &)> Inventory;
147
152
// Tells listeners to broadcast their data.
148
153
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<void (const COutPoint&, const CTransaction&, bool )> DetectedDoubleSpend;
149
160
} g_signals;
150
161
151
162
} // anon namespace
152
163
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 (RelayDoubleSpend, _1, _2, _3, doubleSpendFilter));
170
+ }
171
+
172
+
153
173
void RegisterWallet (CWalletInterface* pwalletIn) {
154
174
g_signals.SyncTransaction .connect (boost::bind (&CWalletInterface::SyncTransaction, pwalletIn, _1, _2));
155
175
g_signals.EraseTransaction .connect (boost::bind (&CWalletInterface::EraseFromWallet, pwalletIn, _1));
@@ -872,6 +892,21 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree,
872
892
return nMinFee;
873
893
}
874
894
895
+ // Exponentially limit the rate of nSize flow to nLimit. nLimit unit is thousands-per-minute.
896
+ bool RateLimitExceeded (double & dCount, int64_t & nLastTime, int64_t nLimit, unsigned int nSize)
897
+ {
898
+ static CCriticalSection csLimiter;
899
+ int64_t nNow = GetTime ();
900
+
901
+ LOCK (csLimiter);
902
+
903
+ dCount *= pow (1.0 - 1.0 /600.0 , (double )(nNow - nLastTime));
904
+ nLastTime = nNow;
905
+ if (dCount >= nLimit*10 *1000 )
906
+ return true ;
907
+ dCount += nSize;
908
+ return false ;
909
+ }
875
910
876
911
bool AcceptToMemoryPool (CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree ,
877
912
bool * pfMissingInputs, bool fRejectInsaneFee )
@@ -906,9 +941,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
906
941
for (unsigned int i = 0 ; i < tx.vin .size (); i++)
907
942
{
908
943
COutPoint outpoint = tx.vin [i].prevout ;
909
- if (pool.mapNextTx .count (outpoint))
944
+ // Does tx conflict with a member of the pool, and is it not equivalent to that member?
945
+ if (pool.mapNextTx .count (outpoint) && !tx.IsEquivalentTo (*pool.mapNextTx [outpoint].ptx ))
910
946
{
911
- // Disable replacement feature for now
947
+ g_signals. DetectedDoubleSpend (outpoint, tx, false );
912
948
return false ;
913
949
}
914
950
}
@@ -980,23 +1016,15 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
980
1016
// be annoying or make others' transactions take longer to confirm.
981
1017
if (fLimitFree && nFees < CTransaction::minRelayTxFee.GetFee (nSize))
982
1018
{
983
- static CCriticalSection csFreeLimiter;
984
1019
static double dFreeCount;
985
- static int64_t nLastTime;
986
- int64_t nNow = GetTime ();
987
-
988
- LOCK (csFreeLimiter);
1020
+ static int64_t nLastFreeTime;
1021
+ static int64_t nFreeLimit = GetArg (" -limitfreerelay" , 15 );
989
1022
990
- // Use an exponentially decaying ~10-minute window:
991
- dFreeCount *= pow (1.0 - 1.0 /600.0 , (double )(nNow - nLastTime));
992
- nLastTime = nNow;
993
- // -limitfreerelay unit is thousand-bytes-per-minute
994
- // At default rate it would take over a month to fill 1GB
995
- if (dFreeCount >= GetArg (" -limitfreerelay" , 15 )*10 *1000 )
1023
+ if (RateLimitExceeded (dFreeCount, nLastFreeTime, nFreeLimit, nSize))
996
1024
return state.DoS (0 , error (" AcceptToMemoryPool : free transaction rejected by rate limiter" ),
997
1025
REJECT_INSUFFICIENTFEE, " insufficient priority" );
1026
+
998
1027
LogPrint (" mempool" , " Rate limit dFreeCount: %g => %g\n " , dFreeCount, dFreeCount+nSize);
999
- dFreeCount += nSize;
1000
1028
}
1001
1029
1002
1030
if (fRejectInsaneFee && nFees > CTransaction::minRelayTxFee.GetFee (nSize) * 10000 )
@@ -1019,6 +1047,48 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
1019
1047
return true ;
1020
1048
}
1021
1049
1050
+ static void RelayDoubleSpend (const COutPoint& outPoint, const CTransaction& doubleSpend, bool fInBlock , CBloomFilter& filter)
1051
+ {
1052
+ // Relaying double-spend attempts to our peers lets them detect when
1053
+ // somebody might be trying to cheat them. However, blindly relaying
1054
+ // every double-spend across the entire network gives attackers
1055
+ // a denial-of-service attack: just generate a stream of double-spends
1056
+ // re-spending the same (limited) set of outpoints owned by the attacker.
1057
+ // So, we use a bloom filter and only relay (at most) the first double
1058
+ // spend for each outpoint. False-positives ("we have already relayed")
1059
+ // are OK, because if the peer doesn't hear about the double-spend
1060
+ // from us they are very likely to hear about it from another peer, since
1061
+ // each peer uses a different, randomized bloom filter.
1062
+
1063
+ if (fInBlock || filter.contains (outPoint)) return ;
1064
+
1065
+ // Apply an independent rate limit to double-spend relays
1066
+ static double dRespendCount;
1067
+ static int64_t nLastRespendTime;
1068
+ static int64_t nRespendLimit = GetArg (" -limitrespendrelay" , 100 );
1069
+ unsigned int nSize = ::GetSerializeSize (doubleSpend, SER_NETWORK, PROTOCOL_VERSION);
1070
+
1071
+ if (RateLimitExceeded (dRespendCount, nLastRespendTime, nRespendLimit, nSize))
1072
+ {
1073
+ LogPrint (" mempool" , " Double-spend relay rejected by rate limiter\n " );
1074
+ return ;
1075
+ }
1076
+
1077
+ LogPrint (" mempool" , " Rate limit dRespendCount: %g => %g\n " , dRespendCount, dRespendCount+nSize);
1078
+
1079
+ // Clear the filter on average every MAX_DOUBLE_SPEND_BLOOM
1080
+ // insertions
1081
+ if (insecure_rand ()%MAX_DOUBLESPEND_BLOOM == 0 )
1082
+ filter.clear ();
1083
+
1084
+ filter.insert (outPoint);
1085
+
1086
+ RelayTransaction (doubleSpend);
1087
+
1088
+ // Share conflict with wallet
1089
+ g_signals.SyncTransaction (doubleSpend, NULL );
1090
+ }
1091
+
1022
1092
1023
1093
int CMerkleTx::GetDepthInMainChainINTERNAL (CBlockIndex* &pindexRet) const
1024
1094
{
0 commit comments