Refactor and fix GetRealOutpointPrivateSendRounds (#3460)

* Refactor and fix GetRealOutpointPrivateSendRounds

Changes:
- streamline logic
- use much more compact/direct map to store outpoint rounds
- per-wallet map instead of a static one
- hold cs_wallet

* Bail out early if one of outputs in the same tx is a non-denom one
This commit is contained in:
UdjinM6 2020-05-11 15:31:20 +03:00 committed by GitHub
parent c06838e205
commit d5f403d3fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 71 deletions

View File

@ -1576,61 +1576,60 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
// Recursively determine the rounds of a given input (How deep is the PrivateSend chain for a given input) // Recursively determine the rounds of a given input (How deep is the PrivateSend chain for a given input)
int CWallet::GetRealOutpointPrivateSendRounds(const COutPoint& outpoint, int nRounds) const int CWallet::GetRealOutpointPrivateSendRounds(const COutPoint& outpoint, int nRounds) const
{ {
static std::map<uint256, CMutableTransaction> mDenomWtxes; LOCK(cs_wallet);
if (nRounds >= MAX_PRIVATESEND_ROUNDS) { if (nRounds >= MAX_PRIVATESEND_ROUNDS) {
// there can only be MAX_PRIVATESEND_ROUNDS rounds max // there can only be MAX_PRIVATESEND_ROUNDS rounds max
return MAX_PRIVATESEND_ROUNDS - 1; return MAX_PRIVATESEND_ROUNDS - 1;
} }
uint256 hash = outpoint.hash; auto pair = mapOutpointRoundsCache.emplace(outpoint, -10);
unsigned int nout = outpoint.n; auto nRoundsRef = &pair.first->second;
if (!pair.second) {
// we already processed it, just return what we have
return *nRoundsRef;
}
// TODO wtx should refer to a CWalletTx object, not a pointer, based on surrounding code // TODO wtx should refer to a CWalletTx object, not a pointer, based on surrounding code
const CWalletTx* wtx = GetWalletTx(hash); const CWalletTx* wtx = GetWalletTx(outpoint.hash);
if(wtx != nullptr)
{
std::map<uint256, CMutableTransaction>::const_iterator mdwi = mDenomWtxes.find(hash);
if (mdwi == mDenomWtxes.end()) {
// not known yet, let's add it
LogPrint(BCLog::PRIVATESEND, "GetRealOutpointPrivateSendRounds INSERTING %s\n", hash.ToString());
mDenomWtxes[hash] = CMutableTransaction(*wtx->tx);
} else if(mDenomWtxes[hash].vout[nout].nRounds != -10) {
// found and it's not an initial value, just return it
return mDenomWtxes[hash].vout[nout].nRounds;
}
if (wtx == nullptr || wtx->tx == nullptr) {
// no such tx in this wallet
*nRoundsRef = -1;
LogPrint(BCLog::PRIVATESEND, "%s FAILED %-70s %3d\n", __func__, outpoint.ToStringShort(), -1);
return *nRoundsRef;
}
// bounds check // bounds check
if (nout >= wtx->tx->vout.size()) { if (outpoint.n >= wtx->tx->vout.size()) {
// should never actually hit this // should never actually hit this
LogPrint(BCLog::PRIVATESEND, "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, -4); *nRoundsRef = -4;
return -4; LogPrint(BCLog::PRIVATESEND, "%s FAILED %-70s %3d\n", __func__, outpoint.ToStringShort(), -4);
return *nRoundsRef;
} }
if (CPrivateSend::IsCollateralAmount(wtx->tx->vout[nout].nValue)) { auto txOutRef = &wtx->tx->vout[outpoint.n];
mDenomWtxes[hash].vout[nout].nRounds = -3;
LogPrint(BCLog::PRIVATESEND, "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); if (CPrivateSend::IsCollateralAmount(txOutRef->nValue)) {
return mDenomWtxes[hash].vout[nout].nRounds; *nRoundsRef = -3;
LogPrint(BCLog::PRIVATESEND, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
return *nRoundsRef;
} }
// make sure the final output is non-denominate // make sure the final output is non-denominate
if (!CPrivateSend::IsDenominatedAmount(wtx->tx->vout[nout].nValue)) { //NOT DENOM if (!CPrivateSend::IsDenominatedAmount(txOutRef->nValue)) { //NOT DENOM
mDenomWtxes[hash].vout[nout].nRounds = -2; *nRoundsRef = -2;
LogPrint(BCLog::PRIVATESEND, "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); LogPrint(BCLog::PRIVATESEND, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
return mDenomWtxes[hash].vout[nout].nRounds; return *nRoundsRef;
} }
bool fAllDenoms = true;
for (const auto& out : wtx->tx->vout) { for (const auto& out : wtx->tx->vout) {
fAllDenoms = fAllDenoms && CPrivateSend::IsDenominatedAmount(out.nValue); if (!CPrivateSend::IsDenominatedAmount(out.nValue)) {
}
// this one is denominated but there is another non-denominated output found in the same tx // this one is denominated but there is another non-denominated output found in the same tx
if (!fAllDenoms) { *nRoundsRef = 0;
mDenomWtxes[hash].vout[nout].nRounds = 0; LogPrint(BCLog::PRIVATESEND, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
LogPrint(BCLog::PRIVATESEND, "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); return *nRoundsRef;
return mDenomWtxes[hash].vout[nout].nRounds; }
} }
int nShortest = -10; // an initial value, should be no way to get this by calculations int nShortest = -10; // an initial value, should be no way to get this by calculations
@ -1646,14 +1645,11 @@ int CWallet::GetRealOutpointPrivateSendRounds(const COutPoint& outpoint, int nRo
} }
} }
} }
mDenomWtxes[hash].vout[nout].nRounds = fDenomFound *nRoundsRef = fDenomFound
? (nShortest >= MAX_PRIVATESEND_ROUNDS - 1 ? MAX_PRIVATESEND_ROUNDS : nShortest + 1) // good, we a +1 to the shortest one but only MAX_PRIVATESEND_ROUNDS rounds max allowed ? (nShortest >= MAX_PRIVATESEND_ROUNDS - 1 ? MAX_PRIVATESEND_ROUNDS : nShortest + 1) // good, we a +1 to the shortest one but only MAX_PRIVATESEND_ROUNDS rounds max allowed
: 0; // too bad, we are the fist one in that chain : 0; // too bad, we are the fist one in that chain
LogPrint(BCLog::PRIVATESEND, "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); LogPrint(BCLog::PRIVATESEND, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
return mDenomWtxes[hash].vout[nout].nRounds; return *nRoundsRef;
}
return nRounds - 1;
} }
// respect current settings // respect current settings

View File

@ -747,6 +747,7 @@ private:
void AddToSpends(const uint256& wtxid); void AddToSpends(const uint256& wtxid);
std::set<COutPoint> setWalletUTXO; std::set<COutPoint> setWalletUTXO;
mutable std::map<COutPoint, int> mapOutpointRoundsCache;
/* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */ /* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
void MarkConflicted(const uint256& hashBlock, const uint256& hashTx); void MarkConflicted(const uint256& hashBlock, const uint256& hashTx);