/// <summary>
    /// Select coins in a way that user can pay without a change output (to increase privacy)
    /// and try to find a solution that requires to pay as little extra amount as possible.
    /// </summary>
    /// <param name="strategy">The strategy determines what the algorithm is looking for.</param>
    /// <param name="target">Target value we want to, ideally, sum up from the input values. </param>
    /// <param name="inputEffectiveValues">Dictionary to map back the effective values to their original SmartCoin. </param>
    /// <returns><c>true</c> if a solution was found, <c>false</c> otherwise.</returns>
    internal static bool TryGetCoins(SelectionStrategy strategy, long target, Dictionary <SmartCoin, long> inputEffectiveValues, [NotNullWhen(true)] out IEnumerable <SmartCoin>?selectedCoins, CancellationToken cancellationToken = default)
    {
        selectedCoins = null;

        BranchAndBound branchAndBound = new();

        bool        foundExactMatch = false;
        List <long>?solution        = null;

        try
        {
            foundExactMatch = branchAndBound.TryGetMatch(strategy, out solution, cancellationToken);
        }
        catch (OperationCanceledException)
        {
            Logger.LogInfo("Computing privacy suggestions was cancelled or timed out.");
        }

        // If we've not found an optimal solution then we will use the best.
        if (!foundExactMatch && strategy.GetBestSelectionFound() is long[] bestSolution)
        {
            solution = bestSolution.ToList();
        }

        if (solution is not null)
        {
            // Sanity check: do not return solution that is much higher or much lower than the target.
            if (solution.Sum() > target * MaxExtraPayment || solution.Sum() < target * MinPaymentThreshold)
            {
                return(false);
            }

            List <SmartCoin> resultCoins = new();
            int i = 0;

            foreach ((SmartCoin smartCoin, long effectiveSatoshis) in inputEffectiveValues)
            {
                // Both arrays are in decreasing order so the first match will be the coin we are looking for.
                if (effectiveSatoshis == solution[i])
                {
                    i++;
                    resultCoins.Add(smartCoin);
                    if (i == solution.Count)
                    {
                        break;
                    }
                }
            }

            selectedCoins = resultCoins;
            return(true);
        }

        return(false);
    }