Exemple #1
0
        protected virtual void SetupJobUpdates()
        {
            if (!poolConfig.EnableInternalStratum)
            {
                return;
            }

            jobRebroadcastTimeout = TimeSpan.FromSeconds(Math.Max(1, poolConfig.JobRebroadcastTimeout));

            var sources       = new List <IObservable <bool> >();
            var cancelTimeout = new List <IObservable <bool> >();

            // collect ports
            var zmq = poolConfig.Daemons
                      .Where(x => !string.IsNullOrEmpty(x.Extra.SafeExtensionDataAs <BitcoinDaemonEndpointConfigExtra>()?.ZmqBlockNotifySocket))
                      .ToDictionary(x => x, x => x.Extra.SafeExtensionDataAs <BitcoinDaemonEndpointConfigExtra>().ZmqBlockNotifySocket);

            if (zmq.Count > 0)
            {
                logger.Info(() => $"[{LogCat}] Subscribing to ZMQ push-updates from {string.Join(", ", zmq.Values)}");

                var newJobsPubSub = daemon.ZmqSubscribe(zmq, BitcoinConstants.ZmqPublisherTopicBlockHash, 2)
                                    .Select(frames =>
                {
                    try
                    {
                        // second frame contains the block hash as binary data
                        if (frames.Length > 1)
                        {
                            var hash = frames[1].ToHexString();
                            return(hash);
                        }
                    }

                    finally
                    {
                        frames.Dispose();
                    }

                    return(null);
                })
                                    .Where(x => x != null)
                                    .DistinctUntilChanged()
                                    .Select(_ => Observable.FromAsync(() => UpdateJob(false, "ZMQ pub/sub")))
                                    .Concat()
                                    .Publish()
                                    .RefCount();

                sources.Add(newJobsPubSub);
                cancelTimeout.Add(newJobsPubSub);
            }

            if (poolConfig.BlockRefreshInterval > 0)
            {
                // periodically update block-template from daemon
                var newJobsPolled = Observable.Interval(TimeSpan.FromMilliseconds(poolConfig.BlockRefreshInterval))
                                    .Select(_ => Observable.FromAsync(() => UpdateJob(false, "RPC polling")))
                                    .Concat()
                                    .Where(isNew => isNew)
                                    .Publish()
                                    .RefCount();

                sources.Add(newJobsPolled);
                cancelTimeout.Add(newJobsPolled);
            }

            else
            {
                // poll for the first successful update after which polling is suspended forever
                var newJobsPolled = Observable.Interval(TimeSpan.FromMilliseconds(poolConfig.BlockRefreshInterval))
                                    .Select(_ => Observable.FromAsync(() => UpdateJob(false, "RPC polling")))
                                    .Concat()
                                    .Where(isNew => isNew)
                                    .Take(1)
                                    .Publish()
                                    .RefCount();

                sources.Add(newJobsPolled);
                cancelTimeout.Add(newJobsPolled);
            }

            // if there haven't been any new jobs for a while, force an update
            var cancelRebroadcast = cancelTimeout.Count > 0 ?
                                    cancelTimeout.Count > 1 ? Observable.Merge(cancelTimeout) : cancelTimeout.First() :
                                    Observable.Never <bool>();

            sources.Add(Observable.Timer(jobRebroadcastTimeout)
                        .TakeUntil(cancelRebroadcast) // cancel timeout if an actual new job has been detected
                        .Do(_ => logger.Debug(() => $"[{LogCat}] No new blocks for {jobRebroadcastTimeout.TotalSeconds} seconds - updating transactions & rebroadcasting work"))
                        .Select(x => Observable.FromAsync(() => UpdateJob(true)))
                        .Concat()
                        .Repeat());

            Jobs = Observable.Merge(sources)
                   .Select(GetJobParamsForStratum);
        }