From b4eae5c48d37362b8a45ac9811f35c4355e6a20f Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 21 Mar 2016 13:58:55 -0700 Subject: [PATCH] Add function to get withdraw outputs which are claim-able --- src/validation.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++++ src/validation.h | 2 + 2 files changed, 95 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 6fc5517fff..69350e9ba7 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1124,10 +1124,103 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus return false; } +bool utxoSort(const std::pair& a, const std::pair& b) { + return a.second > b.second; +} +/** Select Inputs which lock at least nAmount to the given chain */ +bool GetLockedOutputs(const uint256 &genesisHash, const CAmount &nAmount, std::vector >& res) { + res.clear(); + LOCK2(cs_main, mempool.cs); + std::vector > locksCreated; + bool locksChanged = false; + if (!pblocktree->ReadLocksCreated(genesisHash, locksCreated)) + return false; + //For faster random esasure + std::list > locksList; + std::copy(locksCreated.begin(), locksCreated.end(), std::back_inserter(locksList)); + + unsigned int skippedLocks = 0; + while (locksList.size() - skippedLocks > 0) { + uint64_t idx = GetRand(locksList.size() - skippedLocks); + std::list >::iterator it = locksList.begin(); + std::advance(it, idx); + const std::pair &lock = (*it); + + //Erase locks that have been spent in an active block + CCoins coins; + if (!pcoinsTip->GetCoins(lock.first.hash, coins) || !coins.IsAvailable(lock.first.n)) { + locksList.erase(it); + locksChanged = true; + continue; + } + + //Move too-small locks or locks currently spent in mempool to back of list + if (lock.second < nAmount || + mempool.mapNextTx.count(COutPoint(lock.first.hash, lock.first.n))) { + locksList.push_back(lock); + locksList.erase(it); + skippedLocks++; + continue; + } + + assert(coins.vout[lock.first.n].nValue.IsAmount() && coins.vout[lock.first.n].nValue.GetAmount() == lock.second); + res.push_back(lock); + break; + } + if (locksChanged) { + //Convert back for serialization + std::vector > vChangedLocks(locksList.begin(), locksList.end()); + pblocktree->ReWriteLocksCreated(genesisHash, vChangedLocks); + } + //Found single lock large enough + if (res.size()) + return true; + + CAmount nTotal = 0; + //Gather up smaller locked outputs for aggregation. + for (std::list >::iterator it = locksList.begin(); it != locksList.end(); it++) { + CCoins coins; + if (!pcoinsTip->GetCoins(it->first.hash, coins) || !coins.IsAvailable(it->first.n)) { + it = locksList.erase(it); + it--; + locksChanged = true; + continue; + } + + if (mempool.mapNextTx.count(COutPoint(it->first.hash, it->first.n))) + continue; + + assert(coins.vout[it->first.n].nValue.IsAmount() && coins.vout[it->first.n].nValue.GetAmount() == it->second); + res.push_back(*it); + + nTotal += it->second; + assert(MoneyRange(nTotal)); + } + + if (locksChanged) { + //Convert back for serialization + std::vector > vChangedLocks(locksList.begin(), locksList.end()); + pblocktree->ReWriteLocksCreated(genesisHash, vChangedLocks); + } + + if (nTotal < nAmount) { + //TODO: Allow claims-from-mempool + return false; + } + + std::sort(res.begin(), res.end(), utxoSort); + nTotal = 0; + size_t i = 0; + for (; i < res.size() && nTotal < nAmount; i++) + nTotal += res[i].second; + + res.resize(i); + return true; +} ////////////////////////////////////////////////////////////////////////////// // diff --git a/src/validation.h b/src/validation.h index 3b2fe034f6..c0076d0abe 100644 --- a/src/validation.h +++ b/src/validation.h @@ -275,6 +275,8 @@ bool IsInitialBlockDownload(); std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, CTransactionRef &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); +/** Select Inputs which lock at least nAmount to the given chain */ +bool GetLockedOutputs(const uint256 &genesisHash, const CAmount &nAmount, std::vector >& res); /** Find the best known block, and make it the tip of the block chain */ bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr pblock = std::shared_ptr()); CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);