Пример #1
0
 public Task <EstimateSmartFeeResponse> TryEstimateSmartFeeAsync(int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative)
 {
     return(Rpc.TryEstimateSmartFeeAsync(confirmationTarget, estimateMode: estimateMode));
 }
Пример #2
0
        public static async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(this RPCClient 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));
        }
Пример #3
0
        public async Task <IActionResult> GetSynchronizeAsync([FromQuery] string bestKnownBlockHash, [FromQuery] int maxNumberOfFilters, [FromQuery] string estimateSmartFeeMode)
        {
            if (string.IsNullOrWhiteSpace(bestKnownBlockHash))
            {
                return(BadRequest("Invalid block hash is provided."));
            }
            if (maxNumberOfFilters <= 0)
            {
                return(BadRequest("Invalid maxNumberOfFilters is provided."));
            }

            bool estimateSmartFee     = !string.IsNullOrWhiteSpace(estimateSmartFeeMode);
            EstimateSmartFeeMode mode = EstimateSmartFeeMode.Conservative;

            if (estimateSmartFee)
            {
                if (!Enum.TryParse(estimateSmartFeeMode, ignoreCase: true, out mode))
                {
                    return(BadRequest("Invalid estimation mode is provided, possible values: ECONOMICAL/CONSERVATIVE."));
                }
            }

            if (!ModelState.IsValid)
            {
                return(BadRequest("Wrong body is provided."));
            }

            var knownHash = new uint256(bestKnownBlockHash);

            (Height bestHeight, IEnumerable <string> filters) = Global.IndexBuilderService.GetFilterLinesExcluding(knownHash, maxNumberOfFilters, out bool found);

            var response = new SynchronizeResponse();

            response.Filters    = new string[0];
            response.BestHeight = bestHeight;

            if (!found)
            {
                response.FiltersResponseState = FiltersResponseState.BestKnownHashNotFound;
            }
            else if (!filters.Any())
            {
                response.FiltersResponseState = FiltersResponseState.NoNewFilter;
            }
            else
            {
                response.FiltersResponseState = FiltersResponseState.NewFilters;
                response.Filters = filters;
            }

            response.CcjRoundStates = ChaumianCoinJoinController.GetStatesCollection();

            if (estimateSmartFee)
            {
                response.AllFeeEstimate = await BlockchainController.GetAllFeeEstimateAsync(mode);
            }

            response.ExchangeRates = await OffchainController.GetExchangeRatesCollectionAsync();

            return(Ok(response));
        }
Пример #4
0
    public override async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, CancellationToken cancellationToken = default)
    {
        string cacheKey = $"{nameof(EstimateSmartFeeAsync)}:{confirmationTarget}:{estimateMode}";

        return(await Cache.AtomicGetOrCreateAsync(
                   cacheKey,
                   CacheOptions(1, 4, true),
                   () => base.EstimateSmartFeeAsync(confirmationTarget, estimateMode, cancellationToken)).ConfigureAwait(false));
    }
Пример #5
0
        public static async Task <AllFeeEstimate> EstimateAllFeeAsync(this RPCClient rpc, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false, bool tolerateBitcoinCoreBrainfuck = true)
        {
            var rpcStatus = await rpc.GetRpcStatusAsync(CancellationToken.None).ConfigureAwait(false);

            var estimations = await rpc.EstimateHalfFeesAsync(new Dictionary <int, int>(), 2, 0, Constants.SevenDaysConfirmationTarget, 0, estimateMode, simulateIfRegTest, tolerateBitcoinCoreBrainfuck).ConfigureAwait(false);

            var allFeeEstimate = new AllFeeEstimate(estimateMode, estimations, rpcStatus.Synchronized);

            return(allFeeEstimate);
        }
Пример #6
0
        private async Task <EstimateSmartFeeResponse> GetEstimateSmartFeeAsync(int target, EstimateSmartFeeMode mode)
        {
            var cacheKey = $"{nameof(GetEstimateSmartFeeAsync)}_{target}_{Enum.GetName(typeof(EstimateSmartFeeMode), mode)}";

            if (!_cache.TryGetValue(cacheKey, out EstimateSmartFeeResponse feeResponse))
            {
                feeResponse = await RpcClient.EstimateSmartFeeAsync(target, mode);

                var cacheEntryOptions = new MemoryCacheEntryOptions()
                                        .SetAbsoluteExpiration(TimeSpan.FromSeconds(20));

                _cache.Set(cacheKey, feeResponse, cacheEntryOptions);
            }

            return(feeResponse);
        }
Пример #7
0
 public Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative)
 {
     throw new NotImplementedException();
 }
Пример #8
0
        public async Task <IActionResult> GetSynchronizeAsync([FromQuery, Required] string bestKnownBlockHash, [FromQuery, Required] int maxNumberOfFilters, [FromQuery] string?estimateSmartFeeMode = nameof(EstimateSmartFeeMode.Conservative))
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest("Wrong body is provided."));
            }

            bool estimateSmartFee     = !string.IsNullOrWhiteSpace(estimateSmartFeeMode);
            EstimateSmartFeeMode mode = EstimateSmartFeeMode.Conservative;

            if (estimateSmartFee)
            {
                if (!Enum.TryParse(estimateSmartFeeMode, ignoreCase: true, out mode))
                {
                    return(BadRequest("Invalid estimation mode is provided, possible values: ECONOMICAL/CONSERVATIVE."));
                }
            }

            if (!uint256.TryParse(bestKnownBlockHash, out var knownHash))
            {
                return(BadRequest($"Invalid {nameof(bestKnownBlockHash)}."));
            }

            (Height bestHeight, IEnumerable <FilterModel> filters) = Global.IndexBuilderService.GetFilterLinesExcluding(knownHash, maxNumberOfFilters, out bool found);

            var response = new SynchronizeResponse {
                Filters = Enumerable.Empty <FilterModel>(), BestHeight = bestHeight
            };

            if (!found)
            {
                response.FiltersResponseState = FiltersResponseState.BestKnownHashNotFound;
            }
            else if (!filters.Any())
            {
                response.FiltersResponseState = FiltersResponseState.NoNewFilter;
            }
            else
            {
                response.FiltersResponseState = FiltersResponseState.NewFilters;
                response.Filters = filters;
            }

            response.CcjRoundStates = ChaumianCoinJoinController.GetStatesCollection();

            if (estimateSmartFee)
            {
                try
                {
                    response.AllFeeEstimate = await BlockchainController.GetAllFeeEstimateAsync(mode);
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex);
                }
            }

            response.ExchangeRates = await OffchainController.GetExchangeRatesCollectionAsync();

            response.UnconfirmedCoinJoins = await ChaumianCoinJoinController.GetUnconfirmedCoinJoinCollectionAsync();

            return(Ok(response));
        }
        private static EstimateSmartFeeResponse SimulateRegTestFeeEstimation(int confirmationTarget, EstimateSmartFeeMode estimateMode)
        {
            int satoshiPerBytes;

            if (estimateMode == EstimateSmartFeeMode.Conservative)
            {
                satoshiPerBytes = ((Constants.SevenDaysConfirmationTarget + 1 + 6) - confirmationTarget) / 7;
            }
            else             // Economical
            {
                satoshiPerBytes = ((Constants.SevenDaysConfirmationTarget + 1 + 5) - confirmationTarget) / 7;
            }

            Money   feePerK = new Money(satoshiPerBytes * 1000, MoneyUnit.Satoshi);
            FeeRate feeRate = new FeeRate(feePerK);
            var     resp    = new EstimateSmartFeeResponse {
                Blocks = confirmationTarget, FeeRate = feeRate
            };

            return(resp);
        }
Пример #10
0
        public static async Task <AllFeeEstimate> EstimateAllFeeAsync(this RPCClient rpc, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false, bool tolerateBitcoinCoreBrainfuck = true)
        {
            var estimations = await rpc.EstimateHalfFeesAsync(new Dictionary <int, int>(), 2, 0, 1008, 0, estimateMode, simulateIfRegTest, tolerateBitcoinCoreBrainfuck);

            var allFeeEstimate = new AllFeeEstimate(estimateMode, estimations);

            return(allFeeEstimate);
        }
Пример #11
0
        private async Task <EstimateSmartFeeResponse> GetEstimateSmartFeeAsync(int target, EstimateSmartFeeMode mode)
        {
            var cacheKey     = $"{nameof(GetEstimateSmartFeeAsync)}_{target}_{mode}";
            var cacheOptions = new MemoryCacheEntryOptions {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(60)
            };

            return(await Cache.AtomicGetOrCreateAsync(
                       cacheKey,
                       cacheOptions,
                       () => RpcClient.EstimateSmartFeeAsync(target, mode, simulateIfRegTest: true, tryOtherFeeRates: true)));
        }
Пример #12
0
        private static EstimateSmartFeeResponse SimulateRegTestFeeEstimation(int confirmationTarget, EstimateSmartFeeMode estimateMode)
        {
            int staoshiPerBytes;

            if (estimateMode == EstimateSmartFeeMode.Conservative)
            {
                staoshiPerBytes = 6 + confirmationTarget;
            }
            else             // Economical
            {
                staoshiPerBytes = 5 + confirmationTarget;
            }

            var resp = new EstimateSmartFeeResponse {
                Blocks = confirmationTarget, FeeRate = new FeeRate(new Money(staoshiPerBytes * 1000, MoneyUnit.Satoshi))
            };

            return(resp);
        }
Пример #13
0
        public static async Task <EstimateSmartFeeResponse> TryEstimateSmartFeeAsync(this IRPCClient rpc, int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false, bool tryOtherFeeRates = false)
        {
            if (simulateIfRegTest && rpc.Network == Network.RegTest)
            {
                return(SimulateRegTestFeeEstimation(confirmationTarget, estimateMode));
            }

            if (tryOtherFeeRates)
            {
                EstimateSmartFeeResponse response = await rpc.TryEstimateSmartFeeAsync(confirmationTarget, estimateMode);

                if (response is { })
        public static async Task <AllFeeEstimate> EstimateAllFeeAsync(this IRPCClient rpc, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
        {
            var rpcStatus = await rpc.GetRpcStatusAsync(CancellationToken.None).ConfigureAwait(false);

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

            var sanityFeeRate = mempoolInfo.GetSanityFeeRate();
            var estimations   = await rpc.EstimateHalfFeesAsync(new Dictionary <int, int>(), 2, 0, Constants.SevenDaysConfirmationTarget, 0, sanityFeeRate, estimateMode, simulateIfRegTest).ConfigureAwait(false);

            var allFeeEstimate = new AllFeeEstimate(estimateMode, estimations, rpcStatus.Synchronized);

            return(allFeeEstimate);
        }
Пример #15
0
 public virtual async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative)
 {
     return(await Rpc.EstimateSmartFeeAsync(confirmationTarget, estimateMode).ConfigureAwait(false));
 }
Пример #16
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));
        }
Пример #17
0
 public AllFeeEstimate(EstimateSmartFeeMode type, IDictionary <int, int> estimations, bool isAccurate)
 {
     Create(type, estimations, isAccurate);
 }
Пример #18
0
        private static async Task <Dictionary <int, int> > EstimateHalfFeesAsync(this IRPCClient rpc, IDictionary <int, int> estimations, int smallTarget, int smallTargetFee, int largeTarget, int largeTargetFee, 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, estimateMode, simulateIfRegTest);

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

            if (largeTargetFee == 0)
            {
                var largeTargetFeeResult = await rpc.EstimateSmartFeeAsync(largeTarget, 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, 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, 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, estimateMode, simulateIfRegTest);

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

            return(newEstimations);
        }
Пример #19
0
        private async Task <EstimateSmartFeeResponse> GetEstimateSmartFeeAsync(int target, EstimateSmartFeeMode mode)
        {
            var cacheKey = $"{nameof(GetEstimateSmartFeeAsync)}_{target}_{mode}";

            if (!Cache.TryGetValue(cacheKey, out EstimateSmartFeeResponse feeResponse))
            {
                feeResponse = await RpcClient.EstimateSmartFeeAsync(target, mode, simulateIfRegTest : true, tryOtherFeeRates : true);

                var cacheEntryOptions = new MemoryCacheEntryOptions()
                                        .SetAbsoluteExpiration(TimeSpan.FromSeconds(300));

                Cache.Set(cacheKey, feeResponse, cacheEntryOptions);
            }

            return(feeResponse);
        }
Пример #20
0
        private static async Task <Dictionary <int, int> > GetFeeEstimationsAsync(IRPCClient rpc, EstimateSmartFeeMode estimateMode)
        {
            var batchClient = rpc.PrepareBatch();

            var rpcFeeEstimationTasks = Constants.ConfirmationTargets
                                        .Select(target => batchClient.EstimateSmartFeeAsync(target, estimateMode))
                                        .ToList();

            await batchClient.SendBatchAsync().ConfigureAwait(false);

            try
            {
                await Task.WhenAll(rpcFeeEstimationTasks).ConfigureAwait(false);
            }
            catch
            {
                if (rpcFeeEstimationTasks.All(x => x.IsFaulted))
                {
                    throw rpcFeeEstimationTasks[0].Exception?.InnerExceptions[0]
                          ?? new Exception($"{nameof(GetFeeEstimationsAsync)} failed to fetch fee estimations.");
                }
            }

            // EstimateSmartFeeAsync returns the block number where estimate was found - not always what the requested one.
            return(rpcFeeEstimationTasks
                   .Zip(Constants.ConfirmationTargets, (task, target) => (task, target))
                   .Where(x => x.task.IsCompletedSuccessfully)
                   .Select(x => (x.target, feeRate: x.task.Result.FeeRate))
                   .ToDictionary(x => x.target, x => (int)Math.Ceiling(x.feeRate.SatoshiPerByte)));
        }
Пример #21
0
        public override async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative)
        {
            string cacheKey     = $"{nameof(EstimateSmartFeeAsync)}:{confirmationTarget}:{estimateMode}";
            var    cacheOptions = new MemoryCacheEntryOptions
            {
                Size = 1,
                AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(4)
            };

            cacheOptions.AddExpirationToken(new CancellationChangeToken(TipChangeCancellationTokenSource.Token));

            return(await Cache.AtomicGetOrCreateAsync(
                       cacheKey,
                       cacheOptions,
                       () => base.EstimateSmartFeeAsync(confirmationTarget, estimateMode)).ConfigureAwait(false));
        }
Пример #22
0
        public static async Task <EstimateSmartFeeResponse> EstimateSmartFeeAsync(this IRPCClient rpc, int confirmationTarget, 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);

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

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

            return(result);
        }
Пример #23
0
        private static EstimateSmartFeeResponse SimulateRegTestFeeEstimation(int confirmationTarget, EstimateSmartFeeMode estimateMode)
        {
            int satoshiPerByte = estimateMode == EstimateSmartFeeMode.Conservative
                                ? (Constants.SevenDaysConfirmationTarget + 1 + 6 - confirmationTarget) / 7
                                : (Constants.SevenDaysConfirmationTarget + 1 + 5 - confirmationTarget) / 7; // Economical

            Money   feePerK = Money.Satoshis(satoshiPerByte * 1000);
            FeeRate feeRate = new FeeRate(feePerK);
            var     resp    = new EstimateSmartFeeResponse {
                Blocks = confirmationTarget, FeeRate = feeRate
            };

            return(resp);
        }
Пример #24
0
 private static Dictionary <int, int> SimulateRegTestFeeEstimation(EstimateSmartFeeMode estimateMode) =>
 Constants.ConfirmationTargets
 .Select(target => SimulateRegTestFeeEstimation(target, estimateMode))
 .ToDictionary(x => x.Blocks, x => (int)Math.Ceiling(x.FeeRate.SatoshiPerByte));
Пример #25
0
        private static async Task <Dictionary <int, int> > EstimateHalfFeesAsync(this RPCClient 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);
        }
Пример #26
0
        /// <summary>
        /// Estimates fees for 1w, 3d, 1d, 12h, 6h, 3h, 1h, 30m, 20m.
        /// </summary>
        public static async Task <AllFeeEstimate> EstimateAllFeeAsync(this IRPCClient rpc, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
        {
            var smartEstimations = (simulateIfRegTest && rpc.Network == Network.RegTest)
                                ? SimulateRegTestFeeEstimation(estimateMode)
                                : await GetFeeEstimationsAsync(rpc, estimateMode).ConfigureAwait(false);

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

            var sanityFeeRate = mempoolInfo.GetSanityFeeRate();
            var rpcStatus     = await rpc.GetRpcStatusAsync(CancellationToken.None).ConfigureAwait(false);

            var minEstimations = GetFeeEstimationsFromMempoolInfo(mempoolInfo);

            var fixedEstimations = smartEstimations
                                   .GroupJoin(
                minEstimations,
                outer => outer.Key,
                inner => inner.Key,
                (outer, inner) => new { Estimation = outer, MinimumFromMemPool = inner })
                                   .SelectMany(x =>
                                               x.MinimumFromMemPool.DefaultIfEmpty(),
                                               (a, b) => (
                                                   Target: a.Estimation.Key,
                                                   FeeRate: Math.Max((int)sanityFeeRate.SatoshiPerByte, Math.Max(a.Estimation.Value, b.Value))))
                                   .ToDictionary(x => x.Target, x => x.FeeRate);

            return(new AllFeeEstimate(
                       estimateMode,
                       fixedEstimations,
                       rpcStatus.Synchronized));
        }
Пример #27
0
        public static async Task <EstimateSmartFeeResponse> TryEstimateSmartFeeAsync(this RPCClient rpc, int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false, bool tryOtherFeeRates = false)
        {
            if (simulateIfRegTest && rpc.Network == Network.RegTest)
            {
                return(SimulateRegTestFeeEstimation(confirmationTarget, estimateMode));
            }

            if (tryOtherFeeRates)
            {
                EstimateSmartFeeResponse response = await rpc.TryEstimateSmartFeeAsync(confirmationTarget, estimateMode);

                if (response != null)
                {
                    return(response);
                }
                else
                {
                    // Hopefully Bitcoin Core brainfart: https://github.com/bitcoin/bitcoin/issues/14431
                    for (int i = 2; i <= Constants.SevenDaysConfirmationTarget; i++)
                    {
                        response = await rpc.TryEstimateSmartFeeAsync(i, estimateMode);

                        if (response != null)
                        {
                            return(response);
                        }
                    }
                }
                // Let's try one more time, whatever.
            }

            return(await rpc.TryEstimateSmartFeeAsync(confirmationTarget, estimateMode));
        }
        /// <summary>
        /// Estimates fees for 1w, 3d, 1d, 12h, 6h, 3h, 1h, 30m, 20m.
        /// </summary>
        public static async Task <AllFeeEstimate> EstimateAllFeeAsync(this IRPCClient rpc, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
        {
            var estimations = (simulateIfRegTest && rpc.Network == Network.RegTest)
                                ? SimulateRegTestFeeEstimation(estimateMode)
                                : await GetFeeEstimationsAsync(rpc, estimateMode).ConfigureAwait(false);

            var rpcStatus = await rpc.GetRpcStatusAsync(CancellationToken.None).ConfigureAwait(false);

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

            var sanityFeeRate = mempoolInfo.GetSanityFeeRate();

            return(new AllFeeEstimate(
                       estimateMode,
                       estimations.ToDictionary(x => x.Key, x => Math.Max(x.Value, (int)sanityFeeRate.SatoshiPerByte)),
                       rpcStatus.Synchronized));
        }