/// <summary> /// Returns the max of the feerates calculated with a 60% /// threshold required at target / 2, an 85% threshold required at target and a /// 95% threshold required at 2 * target.Each calculation is performed at the /// shortest time horizon which tracks the required target.Conservative /// estimates, however, required the 95% threshold at 2 * target be met for any /// longer time horizons also. /// </summary> public FeeRate EstimateSmartFee(int confTarget, FeeCalculation feeCalc, bool conservative) { lock (this.lockObject) { if (feeCalc != null) { feeCalc.DesiredTarget = confTarget; feeCalc.ReturnedTarget = confTarget; } double median = -1; EstimationResult tempResult = new EstimationResult(); // Return failure if trying to analyze a target we're not tracking if (confTarget <= 0 || confTarget > this.longStats.GetMaxConfirms()) { return(new FeeRate(0)); // error condition } // It's not possible to get reasonable estimates for confTarget of 1 if (confTarget == 1) { confTarget = 2; } int maxUsableEstimate = MaxUsableEstimate(); if (confTarget > maxUsableEstimate && maxUsableEstimate > 1) { confTarget = maxUsableEstimate; } if (feeCalc != null) { feeCalc.ReturnedTarget = confTarget; } if (confTarget <= 1) { return(new FeeRate(0)); // error condition } Guard.Assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints // true is passed to estimateCombined fee for target/2 and target so // that we check the max confirms for shorter time horizons as well. // This is necessary to preserve monotonically increasing estimates. // For non-conservative estimates we do the same thing for 2*target, but // for conservative estimates we want to skip these shorter horizons // checks for 2*target because we are taking the max over all time // horizons so we already have monotonically increasing estimates and // the purpose of conservative estimates is not to let short term // fluctuations lower our estimates by too much. double halfEst = EstimateCombinedFee(confTarget / 2, HalfSuccessPct, true, tempResult); if (feeCalc != null) { feeCalc.Estimation = tempResult; feeCalc.Reason = FeeReason.HalfEstimate; } median = halfEst; double actualEst = EstimateCombinedFee(confTarget, SuccessPct, true, tempResult); if (actualEst > median) { median = actualEst; if (feeCalc != null) { feeCalc.Estimation = tempResult; feeCalc.Reason = FeeReason.FullEstimate; } } double doubleEst = EstimateCombinedFee(2 * confTarget, DoubleSuccessPct, !conservative, tempResult); if (doubleEst > median) { median = doubleEst; if (feeCalc != null) { feeCalc.Estimation = tempResult; feeCalc.Reason = FeeReason.DoubleEstimate; } } if (conservative || median == -1) { double consEst = EstimateConservativeFee(2 * confTarget, tempResult); if (consEst > median) { median = consEst; if (feeCalc != null) { feeCalc.Estimation = tempResult; feeCalc.Reason = FeeReason.Coservative; } } } if (median < 0) { return(new FeeRate(0)); // error condition } return(new FeeRate(Convert.ToInt64(median))); } }