예제 #1
0
        public static async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(this IRPCClient rpc, int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false, bool tryOtherFeeRates = true)
        {
            if (simulateIfRegTest && rpc.Network == Network.RegTest)
            {
                return(SimulateRegTestFeeEstimation(confirmationTarget, estimateMode));
            }

            if (tryOtherFeeRates)
            {
                try
                {
                    return(await rpc.EstimateSmartFeeAsync(confirmationTarget, estimateMode));
                }
                catch (Exception ex) when(ex is RPCException || ex is NoEstimationException)
                {
                    Logger.LogTrace(ex);
                    // Hopefully Bitcoin Core brainfart: https://github.com/bitcoin/bitcoin/issues/14431
                    for (int i = 2; i <= Constants.SevenDaysConfirmationTarget; i++)
                    {
                        try
                        {
                            return(await rpc.EstimateSmartFeeAsync(i, estimateMode));
                        }
                        catch (Exception ex2) when(ex2 is RPCException || ex2 is NoEstimationException)
                        {
                            Logger.LogTrace(ex2);
                        }
                    }
                }
                // Let's try one more time, whatever.
            }

            return(await rpc.EstimateSmartFeeAsync(confirmationTarget, estimateMode));
        }
예제 #2
0
        private static async Task <Dictionary <int, int> > EstimateHalfFeesAsync(this IRPCClient rpc, IDictionary <int, int> estimations, int smallTarget, int smallFee, int largeTarget, int largeFee, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false, bool tolerateBitcoinCoreBrainfuck = true)
        {
            var newEstimations = new Dictionary <int, int>();

            foreach (var est in estimations)
            {
                newEstimations.TryAdd(est.Key, est.Value);
            }

            if (Math.Abs(smallTarget - largeTarget) <= 1)
            {
                return(newEstimations);
            }

            if (smallFee == 0)
            {
                var smallFeeResult = await rpc.EstimateSmartFeeAsync(smallTarget, estimateMode, simulateIfRegTest, tolerateBitcoinCoreBrainfuck);

                smallFee = (int)Math.Ceiling(smallFeeResult.FeeRate.SatoshiPerByte);
                newEstimations.TryAdd(smallTarget, smallFee);
            }

            if (largeFee == 0)
            {
                var largeFeeResult = await rpc.EstimateSmartFeeAsync(largeTarget, estimateMode, simulateIfRegTest, tolerateBitcoinCoreBrainfuck);

                largeFee    = (int)Math.Ceiling(largeFeeResult.FeeRate.SatoshiPerByte);
                largeTarget = largeFeeResult.Blocks;
                newEstimations.TryAdd(largeTarget, largeFee);
            }

            int halfTarget    = (smallTarget + largeTarget) / 2;
            var halfFeeResult = await rpc.EstimateSmartFeeAsync(halfTarget, estimateMode, simulateIfRegTest, tolerateBitcoinCoreBrainfuck);

            int halfFee = (int)Math.Ceiling(halfFeeResult.FeeRate.SatoshiPerByte);

            halfTarget = halfFeeResult.Blocks;
            newEstimations.TryAdd(halfTarget, halfFee);

            if (smallFee != halfFee)
            {
                var smallEstimations = await rpc.EstimateHalfFeesAsync(newEstimations, smallTarget, smallFee, halfTarget, halfFee, estimateMode, simulateIfRegTest, tolerateBitcoinCoreBrainfuck);

                foreach (var est in smallEstimations)
                {
                    newEstimations.TryAdd(est.Key, est.Value);
                }
            }
            if (largeFee != halfFee)
            {
                var largeEstimations = await rpc.EstimateHalfFeesAsync(newEstimations, halfTarget, halfFee, largeTarget, largeFee, estimateMode, simulateIfRegTest, tolerateBitcoinCoreBrainfuck);

                foreach (var est in largeEstimations)
                {
                    newEstimations.TryAdd(est.Key, est.Value);
                }
            }

            return(newEstimations);
        }
예제 #3
0
        public static async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(this IRPCClient rpc, int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
        {
            if (simulateIfRegTest && rpc.Network == Network.RegTest)
            {
                return(SimulateRegTestFeeEstimation(confirmationTarget, estimateMode));
            }

            return(await rpc.EstimateSmartFeeAsync(confirmationTarget, estimateMode));
        }
예제 #4
0
        public static async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(this IRPCClient rpc, int confirmationTarget, FeeRate sanityFeeRate, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
        {
            EstimateSmartFeeResponse result;

            if (simulateIfRegTest && rpc.Network == Network.RegTest)
            {
                result = SimulateRegTestFeeEstimation(confirmationTarget, estimateMode);
            }
            else
            {
                result = await rpc.EstimateSmartFeeAsync(confirmationTarget, estimateMode).ConfigureAwait(false);
            }

            result.FeeRate = FeeRate.Max(sanityFeeRate, result.FeeRate);

            return(result);
        }
예제 #5
0
    public static async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(this IRPCClient rpc, int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false, CancellationToken cancellationToken = default)
    {
        EstimateSmartFeeResponse result;

        if (simulateIfRegTest && rpc.Network == Network.RegTest)
        {
            result = SimulateRegTestFeeEstimation(confirmationTarget, estimateMode);
        }
        else
        {
            result = await rpc.EstimateSmartFeeAsync(confirmationTarget, estimateMode, cancellationToken).ConfigureAwait(false);

            var mempoolInfo = await rpc.GetMempoolInfoAsync(cancellationToken).ConfigureAwait(false);

            result.FeeRate = FeeRate.Max(mempoolInfo.GetSanityFeeRate(), result.FeeRate);
        }

        return(result);
    }
예제 #6
0
        private static async Task <Dictionary <int, int> > EstimateHalfFeesAsync(this IRPCClient rpc, IDictionary <int, int> estimations, int smallTarget, int smallTargetFee, int largeTarget, int largeTargetFee, FeeRate sanityFeeRate, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
        {
            var newEstimations = new Dictionary <int, int>();

            foreach (var est in estimations)
            {
                newEstimations.TryAdd(est.Key, est.Value);
            }

            if (Math.Abs(smallTarget - largeTarget) <= 1)
            {
                return(newEstimations);
            }

            if (smallTargetFee == 0)
            {
                var smallTargetFeeResult = await rpc.EstimateSmartFeeAsync(smallTarget, sanityFeeRate, estimateMode, simulateIfRegTest);

                smallTargetFee = (int)Math.Ceiling(smallTargetFeeResult.FeeRate.SatoshiPerByte);
                newEstimations.TryAdd(smallTarget, smallTargetFee);
            }

            if (largeTargetFee == 0)
            {
                var largeTargetFeeResult = await rpc.EstimateSmartFeeAsync(largeTarget, sanityFeeRate, estimateMode, simulateIfRegTest);

                largeTargetFee = (int)Math.Ceiling(largeTargetFeeResult.FeeRate.SatoshiPerByte);

                // Blocks should never be larger than the target that we asked for, so it's just a sanity check.
                largeTarget = Math.Min(largeTarget, largeTargetFeeResult.Blocks);
                newEstimations.TryAdd(largeTarget, largeTargetFee);
            }

            int halfTarget    = (smallTarget + largeTarget) / 2;
            var halfFeeResult = await rpc.EstimateSmartFeeAsync(halfTarget, sanityFeeRate, estimateMode, simulateIfRegTest);

            int halfTargetFee = (int)Math.Ceiling(halfFeeResult.FeeRate.SatoshiPerByte);

            // Blocks should never be larger than the target that we asked for, so it's just a sanity check.
            halfTarget = Math.Min(halfTarget, halfFeeResult.Blocks);
            newEstimations.TryAdd(halfTarget, halfTargetFee);

            if (smallTargetFee > halfTargetFee)
            {
                var smallEstimations = await rpc.EstimateHalfFeesAsync(newEstimations, smallTarget, smallTargetFee, halfTarget, halfTargetFee, sanityFeeRate, estimateMode, simulateIfRegTest);

                foreach (var est in smallEstimations)
                {
                    newEstimations.TryAdd(est.Key, est.Value);
                }
            }
            if (largeTargetFee < halfTargetFee)
            {
                var largeEstimations = await rpc.EstimateHalfFeesAsync(newEstimations, halfTarget, halfTargetFee, largeTarget, largeTargetFee, sanityFeeRate, estimateMode, simulateIfRegTest);

                foreach (var est in largeEstimations)
                {
                    newEstimations.TryAdd(est.Key, est.Value);
                }
            }

            return(newEstimations);
        }