diff options
| author | Bitflash <btf01@proton.me> | 2026-07-28 15:25:29 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-28 15:25:29 -0300 |
| commit | 8770e49d5264bdc9f6daec61dee74ca74dabdc0a (patch) | |
| tree | 7899739b6619ee355cedda188b58baf9aacdb6c4 | |
| parent | 1635bc34f40c76ac2943dbe6ff15dd0180b62ea6 (diff) | |
main: cap orphan transactions held in memory (#16)
A transaction naming a parent the node does not have is never validated,
just stored in mapOrphanTransactions -- and there was no ceiling. Sending
them costs a peer nothing: no proof of work, no valid signature, no fee,
and the node keeps every one. Any peer could grow that map until the node
died of memory exhaustion.
Cap at 100, evicting at random rather than in map order so an attacker
cannot keep its own orphans resident by choosing hashes that sort low.
Local policy, not consensus -- no effect on block or transaction
validity.
| -rw-r--r-- | src/main.cpp | 20 | ||||
| -rw-r--r-- | src/main.h | 6 |
2 files changed, 26 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp index a7298ea..17e446e 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -249,6 +249,26 @@ void AddOrphanTx(const CDataStream& vMsg) | |||
| 249 | CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg); | 249 | CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg); |
| 250 | foreach(const CTxIn& txin, tx.vin) | 250 | foreach(const CTxIn& txin, tx.vin) |
| 251 | mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg)); | 251 | mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg)); |
| 252 | LimitOrphanTx(MAX_ORPHAN_TRANSACTIONS); | ||
| 253 | } | ||
| 254 | |||
| 255 | // Orphans cost nothing to create -- a transaction naming a parent that does | ||
| 256 | // not exist is never validated, just held -- so without a ceiling any peer can | ||
| 257 | // grow this map until the node runs out of memory. Evict at random rather than | ||
| 258 | // in map order, so an attacker cannot keep its own orphans resident by | ||
| 259 | // choosing hashes that sort low. | ||
| 260 | void LimitOrphanTx(unsigned int nMaxOrphans) | ||
| 261 | { | ||
| 262 | while (mapOrphanTransactions.size() > nMaxOrphans) | ||
| 263 | { | ||
| 264 | uint256 randomhash; | ||
| 265 | for (int i = 0; i < 4; i++) | ||
| 266 | ((uint64*)&randomhash)[i] = GetRand(_UI64_MAX); | ||
| 267 | map<uint256, CDataStream*>::iterator it = mapOrphanTransactions.lower_bound(randomhash); | ||
| 268 | if (it == mapOrphanTransactions.end()) | ||
| 269 | it = mapOrphanTransactions.begin(); | ||
| 270 | EraseOrphanTx(it->first); | ||
| 271 | } | ||
| 252 | } | 272 | } |
| 253 | 273 | ||
| 254 | void EraseOrphanTx(uint256 hash) | 274 | void EraseOrphanTx(uint256 hash) |
| @@ -15,6 +15,9 @@ class CWalletTx; | |||
| 15 | class CKeyItem; | 15 | class CKeyItem; |
| 16 | 16 | ||
| 17 | static const unsigned int MAX_SIZE = 0x02000000; | 17 | static const unsigned int MAX_SIZE = 0x02000000; |
| 18 | // Ceiling on transactions held waiting for a parent that has not arrived. | ||
| 19 | // They cost a peer nothing to send and are never validated, only stored. | ||
| 20 | static const unsigned int MAX_ORPHAN_TRANSACTIONS = 100; | ||
| 18 | static const int64 COIN = 100000000; | 21 | static const int64 COIN = 100000000; |
| 19 | // Total Bitflash emission: identical to Bitcoin (21 million). | 22 | // Total Bitflash emission: identical to Bitcoin (21 million). |
| 20 | // MAX_MONEY guards against the value overflow bug (CVE-2010-5139), which in | 23 | // MAX_MONEY guards against the value overflow bug (CVE-2010-5139), which in |
| @@ -106,6 +109,9 @@ void ReacceptWalletTransactions(); | |||
| 106 | void RelayWalletTransactions(); | 109 | void RelayWalletTransactions(); |
| 107 | bool LoadBlockIndex(bool fAllowNew=true); | 110 | bool LoadBlockIndex(bool fAllowNew=true); |
| 108 | void PrintBlockTree(); | 111 | void PrintBlockTree(); |
| 112 | void AddOrphanTx(const CDataStream& vMsg); | ||
| 113 | void EraseOrphanTx(uint256 hash); | ||
| 114 | void LimitOrphanTx(unsigned int nMaxOrphans); | ||
| 109 | bool BitcoinMiner(); | 115 | bool BitcoinMiner(); |
| 110 | void ThreadRPCServer(void* parg); // rpc.cpp -- .btf pool server | 116 | void ThreadRPCServer(void* parg); // rpc.cpp -- .btf pool server |
| 111 | void GetParticipantMiningStats(uint64& sharesSent, uint64& sharesAccepted, double& hashRate); | 117 | void GetParticipantMiningStats(uint64& sharesSent, uint64& sharesAccepted, double& hashRate); |