@@ -2438,52 +2438,6 @@ const CTxOut& CWallet::FindNonChangeParentOutput(const CTransaction& tx, int out
2438
2438
return ptx->vout [n];
2439
2439
}
2440
2440
2441
- static void ApproximateBestSubset (const std::vector<CInputCoin>& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
2442
- std::vector<char >& vfBest, CAmount& nBest, int iterations = 1000 )
2443
- {
2444
- std::vector<char > vfIncluded;
2445
-
2446
- vfBest.assign (vValue.size (), true );
2447
- nBest = nTotalLower;
2448
-
2449
- FastRandomContext insecure_rand;
2450
-
2451
- for (int nRep = 0 ; nRep < iterations && nBest != nTargetValue; nRep++)
2452
- {
2453
- vfIncluded.assign (vValue.size (), false );
2454
- CAmount nTotal = 0 ;
2455
- bool fReachedTarget = false ;
2456
- for (int nPass = 0 ; nPass < 2 && !fReachedTarget ; nPass++)
2457
- {
2458
- for (unsigned int i = 0 ; i < vValue.size (); i++)
2459
- {
2460
- // The solver here uses a randomized algorithm,
2461
- // the randomness serves no real security purpose but is just
2462
- // needed to prevent degenerate behavior and it is important
2463
- // that the rng is fast. We do not use a constant random sequence,
2464
- // because there may be some privacy improvement by making
2465
- // the selection random.
2466
- if (nPass == 0 ? insecure_rand.randbool () : !vfIncluded[i])
2467
- {
2468
- nTotal += vValue[i].txout .nValue ;
2469
- vfIncluded[i] = true ;
2470
- if (nTotal >= nTargetValue)
2471
- {
2472
- fReachedTarget = true ;
2473
- if (nTotal < nBest)
2474
- {
2475
- nBest = nTotal;
2476
- vfBest = vfIncluded;
2477
- }
2478
- nTotal -= vValue[i].txout .nValue ;
2479
- vfIncluded[i] = false ;
2480
- }
2481
- }
2482
- }
2483
- }
2484
- }
2485
- }
2486
-
2487
2441
bool CWallet::OutputEligibleForSpending (const COutput& output, const CoinEligibilityFilter& eligibilty_filter) const
2488
2442
{
2489
2443
if (!output.fSpendable )
@@ -2504,94 +2458,16 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
2504
2458
setCoinsRet.clear ();
2505
2459
nValueRet = 0 ;
2506
2460
2507
- // List of values less than target
2508
- boost::optional<CInputCoin> coinLowestLarger;
2509
- std::vector<CInputCoin> vValue;
2510
- CAmount nTotalLower = 0 ;
2511
-
2512
- random_shuffle (vCoins.begin (), vCoins.end (), GetRandInt);
2513
-
2461
+ std::vector<CInputCoin> utxo_pool;
2514
2462
for (const COutput &output : vCoins)
2515
2463
{
2516
2464
if (!OutputEligibleForSpending (output, eligibilty_filter))
2517
2465
continue ;
2518
2466
2519
2467
CInputCoin coin = CInputCoin (output.tx ->tx , output.i );
2520
-
2521
- if (coin.txout .nValue == nTargetValue)
2522
- {
2523
- setCoinsRet.insert (coin);
2524
- nValueRet += coin.txout .nValue ;
2525
- return true ;
2526
- }
2527
- else if (coin.txout .nValue < nTargetValue + MIN_CHANGE)
2528
- {
2529
- vValue.push_back (coin);
2530
- nTotalLower += coin.txout .nValue ;
2531
- }
2532
- else if (!coinLowestLarger || coin.txout .nValue < coinLowestLarger->txout .nValue )
2533
- {
2534
- coinLowestLarger = coin;
2535
- }
2536
- }
2537
-
2538
- if (nTotalLower == nTargetValue)
2539
- {
2540
- for (const auto & input : vValue)
2541
- {
2542
- setCoinsRet.insert (input);
2543
- nValueRet += input.txout .nValue ;
2544
- }
2545
- return true ;
2546
- }
2547
-
2548
- if (nTotalLower < nTargetValue)
2549
- {
2550
- if (!coinLowestLarger)
2551
- return false ;
2552
- setCoinsRet.insert (coinLowestLarger.get ());
2553
- nValueRet += coinLowestLarger->txout .nValue ;
2554
- return true ;
2555
- }
2556
-
2557
- // Solve subset sum by stochastic approximation
2558
- std::sort (vValue.begin (), vValue.end (), CompareValueOnly ());
2559
- std::reverse (vValue.begin (), vValue.end ());
2560
- std::vector<char > vfBest;
2561
- CAmount nBest;
2562
-
2563
- ApproximateBestSubset (vValue, nTotalLower, nTargetValue, vfBest, nBest);
2564
- if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE)
2565
- ApproximateBestSubset (vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
2566
-
2567
- // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
2568
- // or the next bigger coin is closer), return the bigger coin
2569
- if (coinLowestLarger &&
2570
- ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger->txout .nValue <= nBest))
2571
- {
2572
- setCoinsRet.insert (coinLowestLarger.get ());
2573
- nValueRet += coinLowestLarger->txout .nValue ;
2468
+ utxo_pool.push_back (coin);
2574
2469
}
2575
- else {
2576
- for (unsigned int i = 0 ; i < vValue.size (); i++)
2577
- if (vfBest[i])
2578
- {
2579
- setCoinsRet.insert (vValue[i]);
2580
- nValueRet += vValue[i].txout .nValue ;
2581
- }
2582
-
2583
- if (LogAcceptCategory (BCLog::SELECTCOINS)) {
2584
- LogPrint (BCLog::SELECTCOINS, " SelectCoins() best subset: " );
2585
- for (unsigned int i = 0 ; i < vValue.size (); i++) {
2586
- if (vfBest[i]) {
2587
- LogPrint (BCLog::SELECTCOINS, " %s " , FormatMoney (vValue[i].txout .nValue ));
2588
- }
2589
- }
2590
- LogPrint (BCLog::SELECTCOINS, " total %s\n " , FormatMoney (nBest));
2591
- }
2592
- }
2593
-
2594
- return true ;
2470
+ return KnapsackSolver (nTargetValue, utxo_pool, setCoinsRet, nValueRet);
2595
2471
}
2596
2472
2597
2473
bool CWallet::SelectCoins (const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
0 commit comments