@ -2438,52 +2438,6 @@ const CTxOut& CWallet::FindNonChangeParentOutput(const CTransaction& tx, int out
return ptx - > vout [ n ] ;
return ptx - > vout [ n ] ;
}
}
static void ApproximateBestSubset ( const std : : vector < CInputCoin > & vValue , const CAmount & nTotalLower , const CAmount & nTargetValue ,
std : : vector < char > & vfBest , CAmount & nBest , int iterations = 1000 )
{
std : : vector < char > vfIncluded ;
vfBest . assign ( vValue . size ( ) , true ) ;
nBest = nTotalLower ;
FastRandomContext insecure_rand ;
for ( int nRep = 0 ; nRep < iterations & & nBest ! = nTargetValue ; nRep + + )
{
vfIncluded . assign ( vValue . size ( ) , false ) ;
CAmount nTotal = 0 ;
bool fReachedTarget = false ;
for ( int nPass = 0 ; nPass < 2 & & ! fReachedTarget ; nPass + + )
{
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + )
{
//The solver here uses a randomized algorithm,
//the randomness serves no real security purpose but is just
//needed to prevent degenerate behavior and it is important
//that the rng is fast. We do not use a constant random sequence,
//because there may be some privacy improvement by making
//the selection random.
if ( nPass = = 0 ? insecure_rand . randbool ( ) : ! vfIncluded [ i ] )
{
nTotal + = vValue [ i ] . txout . nValue ;
vfIncluded [ i ] = true ;
if ( nTotal > = nTargetValue )
{
fReachedTarget = true ;
if ( nTotal < nBest )
{
nBest = nTotal ;
vfBest = vfIncluded ;
}
nTotal - = vValue [ i ] . txout . nValue ;
vfIncluded [ i ] = false ;
}
}
}
}
}
}
bool CWallet : : OutputEligibleForSpending ( const COutput & output , const CoinEligibilityFilter & eligibilty_filter ) const
bool CWallet : : OutputEligibleForSpending ( const COutput & output , const CoinEligibilityFilter & eligibilty_filter ) const
{
{
if ( ! output . fSpendable )
if ( ! output . fSpendable )
@ -2504,94 +2458,16 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
setCoinsRet . clear ( ) ;
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
nValueRet = 0 ;
// List of values less than target
std : : vector < CInputCoin > utxo_pool ;
boost : : optional < CInputCoin > coinLowestLarger ;
std : : vector < CInputCoin > vValue ;
CAmount nTotalLower = 0 ;
random_shuffle ( vCoins . begin ( ) , vCoins . end ( ) , GetRandInt ) ;
for ( const COutput & output : vCoins )
for ( const COutput & output : vCoins )
{
{
if ( ! OutputEligibleForSpending ( output , eligibilty_filter ) )
if ( ! OutputEligibleForSpending ( output , eligibilty_filter ) )
continue ;
continue ;
CInputCoin coin = CInputCoin ( output . tx - > tx , output . i ) ;
CInputCoin coin = CInputCoin ( output . tx - > tx , output . i ) ;
utxo_pool . push_back ( coin ) ;
if ( coin . txout . nValue = = nTargetValue )
{
setCoinsRet . insert ( coin ) ;
nValueRet + = coin . txout . nValue ;
return true ;
}
else if ( coin . txout . nValue < nTargetValue + MIN_CHANGE )
{
vValue . push_back ( coin ) ;
nTotalLower + = coin . txout . nValue ;
}
else if ( ! coinLowestLarger | | coin . txout . nValue < coinLowestLarger - > txout . nValue )
{
coinLowestLarger = coin ;
}
}
if ( nTotalLower = = nTargetValue )
{
for ( const auto & input : vValue )
{
setCoinsRet . insert ( input ) ;
nValueRet + = input . txout . nValue ;
}
return true ;
}
if ( nTotalLower < nTargetValue )
{
if ( ! coinLowestLarger )
return false ;
setCoinsRet . insert ( coinLowestLarger . get ( ) ) ;
nValueRet + = coinLowestLarger - > txout . nValue ;
return true ;
}
// Solve subset sum by stochastic approximation
std : : sort ( vValue . begin ( ) , vValue . end ( ) , CompareValueOnly ( ) ) ;
std : : reverse ( vValue . begin ( ) , vValue . end ( ) ) ;
std : : vector < char > vfBest ;
CAmount nBest ;
ApproximateBestSubset ( vValue , nTotalLower , nTargetValue , vfBest , nBest ) ;
if ( nBest ! = nTargetValue & & nTotalLower > = nTargetValue + MIN_CHANGE )
ApproximateBestSubset ( vValue , nTotalLower , nTargetValue + MIN_CHANGE , vfBest , nBest ) ;
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
// or the next bigger coin is closer), return the bigger coin
if ( coinLowestLarger & &
( ( nBest ! = nTargetValue & & nBest < nTargetValue + MIN_CHANGE ) | | coinLowestLarger - > txout . nValue < = nBest ) )
{
setCoinsRet . insert ( coinLowestLarger . get ( ) ) ;
nValueRet + = coinLowestLarger - > txout . nValue ;
}
}
else {
return KnapsackSolver ( nTargetValue , utxo_pool , setCoinsRet , nValueRet ) ;
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + )
if ( vfBest [ i ] )
{
setCoinsRet . insert ( vValue [ i ] ) ;
nValueRet + = vValue [ i ] . txout . nValue ;
}
if ( LogAcceptCategory ( BCLog : : SELECTCOINS ) ) {
LogPrint ( BCLog : : SELECTCOINS , " SelectCoins() best subset: " ) ;
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + ) {
if ( vfBest [ i ] ) {
LogPrint ( BCLog : : SELECTCOINS , " %s " , FormatMoney ( vValue [ i ] . txout . nValue ) ) ;
}
}
LogPrint ( BCLog : : SELECTCOINS , " total %s \n " , FormatMoney ( nBest ) ) ;
}
}
return true ;
}
}
bool CWallet : : SelectCoins ( const std : : vector < COutput > & vAvailableCoins , const CAmount & nTargetValue , std : : set < CInputCoin > & setCoinsRet , CAmount & nValueRet , const CCoinControl * coinControl ) const
bool CWallet : : SelectCoins ( const std : : vector < COutput > & vAvailableCoins , const CAmount & nTargetValue , std : : set < CInputCoin > & setCoinsRet , CAmount & nValueRet , const CCoinControl * coinControl ) const