Remove relaying of double-spends
This commit is contained in:
@@ -1521,7 +1521,6 @@ bool AppInit2(Config& config, boost::thread_group& threadGroup, CScheduler& sche
|
||||
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
|
||||
StartTorControl(threadGroup, scheduler);
|
||||
|
||||
InitRespendFilter();
|
||||
StartNode(threadGroup, scheduler);
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
|
||||
134
src/main.cpp
134
src/main.cpp
@@ -634,14 +634,6 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
|
||||
|
||||
} // anon namespace
|
||||
|
||||
// Bloom filter to limit respend relays to one
|
||||
static const unsigned int MAX_DOUBLESPEND_BLOOM = 100000;
|
||||
static CBloomFilter doubleSpendFilter;
|
||||
void InitRespendFilter() {
|
||||
seed_insecure_rand();
|
||||
doubleSpendFilter = CBloomFilter(MAX_DOUBLESPEND_BLOOM, 0.01, insecure_rand(), BLOOM_UPDATE_NONE);
|
||||
}
|
||||
|
||||
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
|
||||
LOCK(cs_main);
|
||||
CNodeState *state = State(nodeid);
|
||||
@@ -1119,41 +1111,6 @@ std::string FormatStateMessage(const CValidationState &state)
|
||||
state.GetRejectCode());
|
||||
}
|
||||
|
||||
// Exponentially limit the rate of nSize flow to nLimit. nLimit unit is thousands-per-minute.
|
||||
bool RateLimitExceeded(double& dCount, int64_t& nLastTime, int64_t nLimit, unsigned int nSize)
|
||||
{
|
||||
static CCriticalSection csLimiter;
|
||||
int64_t nNow = GetTime();
|
||||
|
||||
LOCK(csLimiter);
|
||||
|
||||
dCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
|
||||
nLastTime = nNow;
|
||||
if (dCount >= nLimit*10*1000)
|
||||
return true;
|
||||
dCount += nSize;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool RespendRelayExceeded(const CTransaction& doubleSpend)
|
||||
{
|
||||
// Apply an independent rate limit to double-spend relays
|
||||
static double dRespendCount;
|
||||
static int64_t nLastRespendTime;
|
||||
static int64_t nRespendLimit = GetArg("-limitrespendrelay", 100);
|
||||
unsigned int nSize = ::GetSerializeSize(doubleSpend, SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
if (RateLimitExceeded(dRespendCount, nLastRespendTime, nRespendLimit, nSize))
|
||||
{
|
||||
LogPrint("mempool", "Double-spend relay rejected by rate limiter\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
LogPrint("mempool", "Rate limit dRespendCount: %g => %g\n", dRespendCount, dRespendCount+nSize);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee,
|
||||
std::vector<uint256>& vHashTxnToUncache)
|
||||
@@ -1202,65 +1159,18 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool");
|
||||
|
||||
// Check for conflicts with in-memory transactions
|
||||
bool fRespend = false;
|
||||
COutPoint relayForOutpoint;
|
||||
|
||||
set<uint256> setConflicts;
|
||||
{
|
||||
LOCK(pool.cs); // protect pool.mapNextTx
|
||||
BOOST_FOREACH(const CTxIn &txin, tx.vin)
|
||||
{
|
||||
COutPoint outpoint = txin.prevout;
|
||||
// A respend is a tx that conflicts with a member of the pool
|
||||
auto itConflicting = pool.mapNextTx.find(outpoint);
|
||||
auto itConflicting = pool.mapNextTx.find(txin.prevout);
|
||||
if (itConflicting != pool.mapNextTx.end())
|
||||
{
|
||||
fRespend = true;
|
||||
// Relay only one tx per respent outpoint, but not if tx is equivalent to pool member
|
||||
if (!doubleSpendFilter.contains(outpoint) && !tx.IsEquivalentTo(*itConflicting->second))
|
||||
{
|
||||
relayForOutpoint = outpoint;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
const CTransaction *ptxConflicting = itConflicting->second;
|
||||
if (!setConflicts.count(ptxConflicting->GetHash()))
|
||||
{
|
||||
// Allow opt-out of transaction replacement by setting
|
||||
// nSequence >= maxint-1 on all inputs.
|
||||
//
|
||||
// maxint-1 is picked to still allow use of nLockTime by
|
||||
// non-replaceable transactions. All inputs rather than just one
|
||||
// is for the sake of multi-party protocols, where we don't
|
||||
// want a single party to be able to disable replacement.
|
||||
//
|
||||
// The opt-out ignores descendants as anyone relying on
|
||||
// first-seen mempool behavior should be checking all
|
||||
// unconfirmed ancestors anyway; doing otherwise is hopelessly
|
||||
// insecure.
|
||||
bool fReplacementOptOut = true;
|
||||
if (0)
|
||||
{
|
||||
BOOST_FOREACH(const CTxIn &txin, ptxConflicting->vin)
|
||||
{
|
||||
if (txin.nSequence < std::numeric_limits<unsigned int>::max()-1)
|
||||
{
|
||||
fReplacementOptOut = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fReplacementOptOut)
|
||||
return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict");
|
||||
|
||||
setConflicts.insert(ptxConflicting->GetHash());
|
||||
}
|
||||
*/
|
||||
|
||||
// Disable replacement feature for good
|
||||
return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict");
|
||||
}
|
||||
}
|
||||
if (fRespend && (relayForOutpoint.IsNull() || RespendRelayExceeded(tx)))
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1369,15 +1279,22 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
// be annoying or make others' transactions take longer to confirm.
|
||||
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
|
||||
{
|
||||
static CCriticalSection csFreeLimiter;
|
||||
static double dFreeCount;
|
||||
static int64_t nLastFreeTime;
|
||||
static int64_t nFreeLimit = GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY);
|
||||
static int64_t nLastTime;
|
||||
int64_t nNow = GetTime();
|
||||
|
||||
LOCK(csFreeLimiter);
|
||||
|
||||
// Use an exponentially decaying ~10-minute window:
|
||||
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
|
||||
nLastTime = nNow;
|
||||
// -limitfreerelay unit is thousand-bytes-per-minute
|
||||
// At default rate it would take over a month to fill 1GB
|
||||
if (RateLimitExceeded(dFreeCount, nLastFreeTime, nFreeLimit, nSize))
|
||||
if (dFreeCount + nSize >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000)
|
||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction");
|
||||
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
|
||||
dFreeCount += nSize;
|
||||
}
|
||||
|
||||
if (nAbsurdFee && nFees > nAbsurdFee)
|
||||
@@ -1571,19 +1488,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
}
|
||||
pool.RemoveStaged(allConflicting, false);
|
||||
|
||||
if (fRespend)
|
||||
{
|
||||
// Clear the filter on average every MAX_DOUBLE_SPEND_BLOOM insertions
|
||||
if (insecure_rand()%MAX_DOUBLESPEND_BLOOM == 0)
|
||||
doubleSpendFilter.clear();
|
||||
doubleSpendFilter.insert(relayForOutpoint);
|
||||
RelayTransaction(tx);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store transaction in memory
|
||||
pool.addUnchecked(hash, entry, !IsInitialBlockDownload());
|
||||
}
|
||||
// Store transaction in memory
|
||||
pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
|
||||
|
||||
// trim mempool and check if tx was trimmed
|
||||
if (!fOverrideMempoolLimit) {
|
||||
@@ -1593,9 +1499,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
}
|
||||
}
|
||||
|
||||
SyncWithWallets(tx, NULL, NULL, fRespend);
|
||||
SyncWithWallets(tx, NULL, NULL);
|
||||
|
||||
return !fRespend;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
@@ -2888,7 +2794,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
|
||||
// Let wallets know transactions went from 1-confirmed to
|
||||
// 0-confirmed or conflicted:
|
||||
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
|
||||
SyncWithWallets(tx, pindexDelete->pprev, NULL, false);
|
||||
SyncWithWallets(tx, pindexDelete->pprev, NULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2947,11 +2853,11 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
|
||||
// Tell wallet about transactions that went from mempool
|
||||
// to conflicted:
|
||||
BOOST_FOREACH(const CTransaction &tx, txConflicted) {
|
||||
SyncWithWallets(tx, pindexNew, NULL, false);
|
||||
SyncWithWallets(tx, pindexNew, NULL);
|
||||
}
|
||||
// ... and about transactions that got confirmed:
|
||||
BOOST_FOREACH(const CTransaction &tx, pblock->vtx) {
|
||||
SyncWithWallets(tx, pindexNew, pblock, false);
|
||||
SyncWithWallets(tx, pindexNew, pblock);
|
||||
}
|
||||
|
||||
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
|
||||
|
||||
@@ -189,9 +189,6 @@ extern CBlockIndex *pindexBestHeader;
|
||||
/** Minimum disk space required - used in CheckDiskSpace() */
|
||||
static const uint64_t nMinDiskSpace = 52428800;
|
||||
|
||||
/** Initialize respend bloom filter **/
|
||||
void InitRespendFilter();
|
||||
|
||||
/** Pruning-related variables and constants */
|
||||
/** True if any block files have ever been pruned. */
|
||||
extern bool fHavePruned;
|
||||
|
||||
@@ -95,15 +95,6 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CTransaction::IsEquivalentTo(const CTransaction& tx) const
|
||||
{
|
||||
CMutableTransaction tx1 = *this;
|
||||
CMutableTransaction tx2 = tx;
|
||||
for (unsigned int i = 0; i < tx1.vin.size(); i++) tx1.vin[i].scriptSig = CScript();
|
||||
for (unsigned int i = 0; i < tx2.vin.size(); i++) tx2.vin[i].scriptSig = CScript();
|
||||
return CTransaction(tx1) == CTransaction(tx2);
|
||||
}
|
||||
|
||||
CAmount CTransaction::GetValueOut() const
|
||||
{
|
||||
CAmount nValueOut = 0;
|
||||
|
||||
@@ -272,9 +272,6 @@ public:
|
||||
return hash;
|
||||
}
|
||||
|
||||
// True if only scriptSigs are different
|
||||
bool IsEquivalentTo(const CTransaction& tx) const;
|
||||
|
||||
// Return sum of txouts.
|
||||
CAmount GetValueOut() const;
|
||||
// GetValueIn() is a method on CCoinsViewCache, because
|
||||
|
||||
@@ -571,6 +571,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
|
||||
void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed)
|
||||
{
|
||||
// Remove transactions which depend on inputs of tx, recursively
|
||||
list<CTransaction> result;
|
||||
LOCK(cs);
|
||||
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
||||
auto it = mapNextTx.find(txin.prevout);
|
||||
|
||||
@@ -14,7 +14,7 @@ CMainSignals& GetMainSignals()
|
||||
|
||||
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||
g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
|
||||
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3, _4));
|
||||
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
|
||||
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
||||
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
||||
@@ -32,7 +32,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
||||
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
||||
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
||||
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3, _4));
|
||||
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
|
||||
g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
|
||||
}
|
||||
|
||||
@@ -48,6 +48,6 @@ void UnregisterAllValidationInterfaces() {
|
||||
g_signals.UpdatedBlockTip.disconnect_all_slots();
|
||||
}
|
||||
|
||||
void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock, bool fRespend) {
|
||||
g_signals.SyncTransaction(tx, pindex, pblock, fRespend);
|
||||
void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) {
|
||||
g_signals.SyncTransaction(tx, pindex, pblock);
|
||||
}
|
||||
|
||||
@@ -27,12 +27,12 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn);
|
||||
/** Unregister all wallets from core */
|
||||
void UnregisterAllValidationInterfaces();
|
||||
/** Push an updated transaction to all registered wallets */
|
||||
void SyncWithWallets(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock = NULL, bool fRespend = false);
|
||||
void SyncWithWallets(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock = NULL);
|
||||
|
||||
class CValidationInterface {
|
||||
protected:
|
||||
virtual void UpdatedBlockTip(const CBlockIndex *pindex) {}
|
||||
virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock, bool fRespend) {}
|
||||
virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, const CBlock *pblock) {}
|
||||
virtual void SetBestChain(const CBlockLocator &locator) {}
|
||||
virtual void UpdatedTransaction(const uint256 &hash) {}
|
||||
virtual void Inventory(const uint256 &hash) {}
|
||||
@@ -49,7 +49,7 @@ struct CMainSignals {
|
||||
/** Notifies listeners of updated block chain tip */
|
||||
boost::signals2::signal<void (const CBlockIndex *)> UpdatedBlockTip;
|
||||
/** Notifies listeners of updated transaction data (transaction, optionally the block it is found in, and whether this is a known respend. */
|
||||
boost::signals2::signal<void (const CTransaction &, const CBlockIndex *pindex, const CBlock *, bool)> SyncTransaction;
|
||||
boost::signals2::signal<void (const CTransaction &, const CBlockIndex *pindex, const CBlock *)> SyncTransaction;
|
||||
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
|
||||
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
|
||||
/** Notifies listeners of a new active block chain. */
|
||||
|
||||
@@ -398,7 +398,7 @@ bool CWallet::SetMaxVersion(int nVersion)
|
||||
return true;
|
||||
}
|
||||
|
||||
set<uint256> CWallet::GetConflicts(const uint256& txid, bool includeEquivalent) const
|
||||
set<uint256> CWallet::GetConflicts(const uint256& txid) const
|
||||
{
|
||||
set<uint256> result;
|
||||
AssertLockHeld(cs_wallet);
|
||||
@@ -416,8 +416,7 @@ set<uint256> CWallet::GetConflicts(const uint256& txid, bool includeEquivalent)
|
||||
continue; // No conflict if zero or one spends
|
||||
range = mapTxSpends.equal_range(txin.prevout);
|
||||
for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
|
||||
if (includeEquivalent || !wtx.IsEquivalentTo(mapWallet.at(it->second)))
|
||||
result.insert(it->second);
|
||||
result.insert(it->second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1199,7 +1198,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD
|
||||
* pblock is optional, but should be provided if the transaction is known to be in a block.
|
||||
* If fUpdate is true, existing transactions will be updated.
|
||||
*/
|
||||
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fRespend)
|
||||
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
|
||||
{
|
||||
{
|
||||
AssertLockHeld(cs_wallet);
|
||||
@@ -1219,15 +1218,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
|
||||
|
||||
bool fExisted = mapWallet.count(tx.GetHash()) != 0;
|
||||
if (fExisted && !fUpdate) return false;
|
||||
|
||||
bool fIsConflicting = IsConflicting(tx);
|
||||
// Don't add respends that pay us, unless they conflict with us. Prevents resource exhaustion.
|
||||
if (!fIsConflicting && fRespend) return false;
|
||||
|
||||
if (fIsConflicting)
|
||||
nConflictsReceived++;
|
||||
|
||||
if (fExisted || IsMine(tx) || IsFromMe(tx) || fIsConflicting)
|
||||
if (fExisted || IsMine(tx) || IsFromMe(tx))
|
||||
{
|
||||
CWalletTx wtx(this,tx);
|
||||
|
||||
@@ -1362,7 +1353,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock, bool fRespend)
|
||||
void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock)
|
||||
{
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
|
||||
@@ -1376,7 +1367,7 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex,
|
||||
}
|
||||
}
|
||||
|
||||
if (!AddToWalletIfInvolvingMe(tx, pblock, true, fRespend))
|
||||
if (!AddToWalletIfInvolvingMe(tx, pblock, true))
|
||||
return; // Not one of ours
|
||||
|
||||
// If a transaction changes 'conflicted' state, that changes the balance
|
||||
@@ -1389,7 +1380,6 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isminetype CWallet::IsMine(const CTxIn &txin) const
|
||||
{
|
||||
{
|
||||
@@ -1405,14 +1395,6 @@ isminetype CWallet::IsMine(const CTxIn &txin) const
|
||||
return ISMINE_NO;
|
||||
}
|
||||
|
||||
bool CWallet::IsConflicting(const CTransaction& tx) const
|
||||
{
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
if (mapTxSpends.count(txin.prevout))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
|
||||
{
|
||||
{
|
||||
@@ -1756,7 +1738,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||
ReadBlockFromDisk(block, pindex, Params().GetConsensus());
|
||||
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
||||
{
|
||||
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate, false))
|
||||
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
|
||||
ret++;
|
||||
}
|
||||
pindex = chainActive.Next(pindex);
|
||||
@@ -1791,7 +1773,8 @@ void CWallet::ReacceptWalletTransactions()
|
||||
assert(wtx.GetHash() == wtxid);
|
||||
|
||||
int nDepth = wtx.GetDepthInMainChain();
|
||||
if (!(wtx.IsCoinBase() || wtx.IsCoinStake()) && (nDepth == 0 && !wtx.isAbandoned()) && (IsMine(wtx) || IsFromMe(wtx))){
|
||||
|
||||
if (!wtx.IsCoinBase() && !wtx.IsCoinStake() && (nDepth == 0 && !wtx.isAbandoned())) {
|
||||
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
|
||||
}
|
||||
}
|
||||
@@ -1823,13 +1806,13 @@ bool CWalletTx::RelayWalletTransaction()
|
||||
return false;
|
||||
}
|
||||
|
||||
set<uint256> CWalletTx::GetConflicts(bool includeEquivalent) const
|
||||
set<uint256> CWalletTx::GetConflicts() const
|
||||
{
|
||||
set<uint256> result;
|
||||
if (pwallet != NULL)
|
||||
{
|
||||
uint256 myHash = GetHash();
|
||||
result = pwallet->GetConflicts(myHash, includeEquivalent);
|
||||
result = pwallet->GetConflicts(myHash);
|
||||
result.erase(myHash);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -412,7 +412,7 @@ public:
|
||||
|
||||
bool RelayWalletTransaction();
|
||||
|
||||
std::set<uint256> GetConflicts(bool includeEquivalent=true) const;
|
||||
std::set<uint256> GetConflicts() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -759,8 +759,8 @@ public:
|
||||
|
||||
void MarkDirty();
|
||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
|
||||
void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock, bool fRespend);
|
||||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fRespend);
|
||||
void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, const CBlock* pblock);
|
||||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
|
||||
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
|
||||
void ReacceptWalletTransactions();
|
||||
void ResendWalletTransactions(int64_t nBestBlockTime);
|
||||
@@ -830,7 +830,6 @@ public:
|
||||
bool IsMine(const CTransaction& tx) const;
|
||||
/** should probably be renamed to IsRelevantToMe */
|
||||
bool IsFromMe(const CTransaction& tx) const;
|
||||
bool IsConflicting(const CTransaction& tx) const;
|
||||
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
|
||||
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
||||
CAmount GetChange(const CTransaction& tx) const;
|
||||
@@ -883,7 +882,7 @@ public:
|
||||
void DisableTransaction(const CTransaction &tx);
|
||||
|
||||
//! Get wallet transactions that conflict with given transaction (spend same outputs)
|
||||
std::set<uint256> GetConflicts(const uint256& txid, bool includeEquivalent) const;
|
||||
std::set<uint256> GetConflicts(const uint256& txid) const;
|
||||
|
||||
//! Flush wallet (bitdb flush)
|
||||
void Flush(bool shutdown=false);
|
||||
|
||||
Reference in New Issue
Block a user