process orphan transactions after processing replacements
This commit is contained in:
@@ -1,19 +1,19 @@
|
|||||||
#ifndef KOMODO_CRYPTOCONDITIONS_H
|
#ifndef KOMODO_CRYPTOCONDITIONS_H
|
||||||
#define KOMODO_CRYPTOCONDITIONS_H
|
#define KOMODO_CRYPTOCONDITIONS_H
|
||||||
|
|
||||||
#include "coins.h"
|
|
||||||
#include "replacementpool.h"
|
#include "replacementpool.h"
|
||||||
#include "cryptoconditions/include/cryptoconditions.h"
|
#include "cryptoconditions/include/cryptoconditions.h"
|
||||||
|
|
||||||
extern int32_t ASSETCHAINS_CC;
|
extern int32_t ASSETCHAINS_CC;
|
||||||
|
|
||||||
extern CTxReplacementPool replacementPool;
|
|
||||||
|
|
||||||
static bool IsCryptoConditionsEnabled() {
|
static bool IsCryptoConditionsEnabled() {
|
||||||
return 0 != ASSETCHAINS_CC;
|
return 0 != ASSETCHAINS_CC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern CTxReplacementPool replacementPool;
|
||||||
|
|
||||||
bool EvalConditionBool(const CC *cond, const CTransaction *tx);
|
bool EvalConditionBool(const CC *cond, const CTransaction *tx);
|
||||||
//uint64_t EvalConditionPriority(const CC *cond, const CTransaction *tx);
|
|
||||||
bool SetReplacementParams(CTxReplacementPoolItem &rep);
|
bool SetReplacementParams(CTxReplacementPoolItem &rep);
|
||||||
|
|
||||||
#endif /* KOMODO_CRYPTOCONDITIONS_H */
|
#endif /* KOMODO_CRYPTOCONDITIONS_H */
|
||||||
|
|||||||
126
src/main.cpp
126
src/main.cpp
@@ -1446,13 +1446,17 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProcessOrphanTransactions(uint256 initialHash);
|
||||||
|
|
||||||
void ProcessReplacementPool(int newHeight)
|
void ProcessReplacementPool(int newHeight)
|
||||||
{
|
{
|
||||||
std::vector<CTransaction> pending;
|
std::vector<CTransaction> pending;
|
||||||
replacementPool.removePending(newHeight, pending);
|
replacementPool.removePending(newHeight, pending);
|
||||||
CValidationState stateDummy;
|
CValidationState stateDummy;
|
||||||
BOOST_FOREACH(CTransaction tx, pending) {
|
BOOST_FOREACH(CTransaction tx, pending) {
|
||||||
AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, false, false);
|
if (AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, false, false))
|
||||||
|
ProcessOrphanTransactions(tx.GetHash());
|
||||||
|
// otherwise silently drop. TODO: log
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4690,6 +4694,70 @@ void static ProcessGetData(CNode* pfrom)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProcessOrphanTransactions(uint256 parentHash)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
|
vector<uint256> vWorkQueue, vEraseQueue;
|
||||||
|
// Recursively process any orphan transactions that depended on this one
|
||||||
|
vWorkQueue.push_back(parentHash);
|
||||||
|
set<NodeId> setMisbehaving;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
|
||||||
|
{
|
||||||
|
map<uint256, set<uint256> >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]);
|
||||||
|
if (itByPrev == mapOrphanTransactionsByPrev.end())
|
||||||
|
continue;
|
||||||
|
for (set<uint256>::iterator mi = itByPrev->second.begin();
|
||||||
|
mi != itByPrev->second.end();
|
||||||
|
++mi)
|
||||||
|
{
|
||||||
|
const uint256& orphanHash = *mi;
|
||||||
|
const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx;
|
||||||
|
NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer;
|
||||||
|
bool fMissingInputs2 = false;
|
||||||
|
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
|
||||||
|
// resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
|
||||||
|
// anyone relaying LegitTxX banned)
|
||||||
|
CValidationState stateDummy;
|
||||||
|
|
||||||
|
|
||||||
|
if (setMisbehaving.count(fromPeer))
|
||||||
|
continue;
|
||||||
|
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
|
||||||
|
{
|
||||||
|
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
|
||||||
|
RelayTransaction(orphanTx);
|
||||||
|
vWorkQueue.push_back(orphanHash);
|
||||||
|
vEraseQueue.push_back(orphanHash);
|
||||||
|
}
|
||||||
|
else if (!fMissingInputs2)
|
||||||
|
{
|
||||||
|
int nDos = 0;
|
||||||
|
if (stateDummy.IsInvalid(nDos) && nDos > 0)
|
||||||
|
{
|
||||||
|
// Punish peer that gave us an invalid orphan tx
|
||||||
|
Misbehaving(fromPeer, nDos);
|
||||||
|
setMisbehaving.insert(fromPeer);
|
||||||
|
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
|
||||||
|
}
|
||||||
|
// Has inputs but not accepted to mempool
|
||||||
|
// Probably non-standard or insufficient fee/priority
|
||||||
|
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
|
||||||
|
vEraseQueue.push_back(orphanHash);
|
||||||
|
assert(recentRejects);
|
||||||
|
recentRejects->insert(orphanHash);
|
||||||
|
}
|
||||||
|
mempool.check(pcoinsTip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FOREACH(uint256 hash, vEraseQueue)
|
||||||
|
EraseOrphanTx(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
|
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
|
||||||
{
|
{
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
@@ -5090,8 +5158,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
|
|
||||||
else if (strCommand == "tx")
|
else if (strCommand == "tx")
|
||||||
{
|
{
|
||||||
vector<uint256> vWorkQueue;
|
|
||||||
vector<uint256> vEraseQueue;
|
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
vRecv >> tx;
|
vRecv >> tx;
|
||||||
|
|
||||||
@@ -5110,66 +5176,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||||||
{
|
{
|
||||||
mempool.check(pcoinsTip);
|
mempool.check(pcoinsTip);
|
||||||
RelayTransaction(tx);
|
RelayTransaction(tx);
|
||||||
vWorkQueue.push_back(inv.hash);
|
|
||||||
|
|
||||||
LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n",
|
LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n",
|
||||||
pfrom->id, pfrom->cleanSubVer,
|
pfrom->id, pfrom->cleanSubVer,
|
||||||
tx.GetHash().ToString(),
|
tx.GetHash().ToString(),
|
||||||
mempool.mapTx.size());
|
mempool.mapTx.size());
|
||||||
|
|
||||||
// Recursively process any orphan transactions that depended on this one
|
ProcessOrphanTransactions(inv.hash);
|
||||||
set<NodeId> setMisbehaving;
|
|
||||||
for (unsigned int i = 0; i < vWorkQueue.size(); i++)
|
|
||||||
{
|
|
||||||
map<uint256, set<uint256> >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]);
|
|
||||||
if (itByPrev == mapOrphanTransactionsByPrev.end())
|
|
||||||
continue;
|
|
||||||
for (set<uint256>::iterator mi = itByPrev->second.begin();
|
|
||||||
mi != itByPrev->second.end();
|
|
||||||
++mi)
|
|
||||||
{
|
|
||||||
const uint256& orphanHash = *mi;
|
|
||||||
const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx;
|
|
||||||
NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer;
|
|
||||||
bool fMissingInputs2 = false;
|
|
||||||
// Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
|
|
||||||
// resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
|
|
||||||
// anyone relaying LegitTxX banned)
|
|
||||||
CValidationState stateDummy;
|
|
||||||
|
|
||||||
|
|
||||||
if (setMisbehaving.count(fromPeer))
|
|
||||||
continue;
|
|
||||||
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2))
|
|
||||||
{
|
|
||||||
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
|
|
||||||
RelayTransaction(orphanTx);
|
|
||||||
vWorkQueue.push_back(orphanHash);
|
|
||||||
vEraseQueue.push_back(orphanHash);
|
|
||||||
}
|
|
||||||
else if (!fMissingInputs2)
|
|
||||||
{
|
|
||||||
int nDos = 0;
|
|
||||||
if (stateDummy.IsInvalid(nDos) && nDos > 0)
|
|
||||||
{
|
|
||||||
// Punish peer that gave us an invalid orphan tx
|
|
||||||
Misbehaving(fromPeer, nDos);
|
|
||||||
setMisbehaving.insert(fromPeer);
|
|
||||||
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
|
|
||||||
}
|
|
||||||
// Has inputs but not accepted to mempool
|
|
||||||
// Probably non-standard or insufficient fee/priority
|
|
||||||
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
|
|
||||||
vEraseQueue.push_back(orphanHash);
|
|
||||||
assert(recentRejects);
|
|
||||||
recentRejects->insert(orphanHash);
|
|
||||||
}
|
|
||||||
mempool.check(pcoinsTip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_FOREACH(uint256 hash, vEraseQueue)
|
|
||||||
EraseOrphanTx(hash);
|
|
||||||
}
|
}
|
||||||
// TODO: currently, prohibit joinsplits from entering mapOrphans
|
// TODO: currently, prohibit joinsplits from entering mapOrphans
|
||||||
else if (fMissingInputs && tx.vjoinsplit.size() == 0)
|
else if (fMissingInputs && tx.vjoinsplit.size() == 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user