예제 #1
0
 /// <summary>
 /// Create a new instance of this class.
 /// </summary>
 /// <param name="deadline">
 /// The duration of the deadline.
 /// </param>
 /// <param name="scoop">
 /// The scoop the dealdine came from.
 /// The</param>
 /// <param name="miningInfo">
 /// The information about the network that this deadline was found matching.
 /// </param>
 public Deadline(TimeSpan deadline, Scoop scoop, MiningInfo miningInfo)
 {
     Status             = DeadlineStatus.Found;
     DeadlineDuration   = deadline;
     Scoop              = scoop;
     MiningInfo         = miningInfo;
     NextSubmissionDate = DateTime.UtcNow;
 }
예제 #2
0
 /// <summary>
 /// Resets the queue and specifies the current block height.  Any scoops received for different block heights will be ignored.
 /// </summary>
 /// <param name="miningInfo">
 /// The details of which block is currently being processed.
 /// </param>
 public void NotifyNewRound(MiningInfo miningInfo)
 {
     // Store the information and then clear the queue
     lock (_scoopQueueLocker)
     {
         _miningInfo = miningInfo;
         _scoopQueue.Clear();
     }
 }
예제 #3
0
        /// <summary>
        /// Starts reading plots for the specifed information and terminates and current plot mining.
        /// </summary>
        /// <param name="miningInfo">
        /// The information to use to commence mining.
        /// </param>
        public void NotifyNewRound(MiningInfo miningInfo)
        {
            // Store this value
            _lastRoundStart = DateTime.UtcNow;
            _miningInfo     = miningInfo;

            // First let's kill any existing plot reading
            foreach (PlotReader reader in _plotReaders)
            {
                reader.Terminate();
            }

            // If no mining information stop now
            if (miningInfo == null)
            {
                return;
            }

            // Throw error if we have no readers
            if (_plotReaders == null)
            {
                Logger.Warn("Unable to process new block " + miningInfo.BlockHeight + ", no plot readers available");
                return;
            }

            // Now we perform our basics to determine scoop number
            byte[] gensigHashable = new byte[40];
            Array.Copy(miningInfo.PreviousGenerationSignatureBytes, gensigHashable, 32);
            Array.Copy(miningInfo.BlockHeightBytes, 0, gensigHashable, 32, 8);
            byte[] gensig = _shabel.ComputeBytes(gensigHashable).GetBytes();
            uint   scoop  = (uint)((gensig[gensig.Length - 2] & 0x0F) << 8) | (gensig[gensig.Length - 1]);

            Logger.Debug("Calculated scoop for block as " + scoop);

            // Update our capacity values
            decimal utilisedStorage = 0;

            foreach (PlotReader reader in _plotReaders)
            {
                utilisedStorage += reader.UtilisedStorage;
            }
            if (UtilisedStorage != utilisedStorage)
            {
                UtilisedStorage = utilisedStorage;
                UtilisedStorageUpdated?.Invoke(this, new UtilisedStorageEventHandler(utilisedStorage));
            }

            // With the config that we have we can now execute all of our readers
            foreach (PlotReader reader in _plotReaders)
            {
                reader.StartMining(miningInfo, scoop);
            }
        }
예제 #4
0
 /// <summary>
 /// Commence mining for the current block.
 /// </summary>
 /// <param name="miningInfo">
 /// Information used during the mining session including current network parameters.
 /// </param>
 /// <param name="scoop">
 /// The scoop that this session will use.
 /// </param>
 internal void StartMining(MiningInfo miningInfo, uint scoop)
 {
     if (_miningThread != null || _isAlive)
     {
         throw new Exception("Thread is already mining");
     }
     _miningInfo = miningInfo;
     _scoop      = scoop;
     Logger.Info("Mining " + _directory + " for block " + miningInfo.BlockHeight + " with scoop " + scoop);
     _isAlive      = true;
     _miningThread = new Thread(ThreadEntry)
     {
         Name = "Plot Reader: " + _directory, IsBackground = true
     };
     _miningThread.Start();
 }
예제 #5
0
 /// <summary>
 /// The main thread entry point that continually checks for changes to mining state in the background.
 /// </summary>
 private void MiningInfoThread()
 {
     while (_isAlive)
     {
         try
         {
             string stringResponse;
             HttpResponseMessage response = _client.GetAsync("/burst?requestType=getMiningInfo").Result;
             response.EnsureSuccessStatusCode();
             stringResponse = response.Content.ReadAsStringAsync().Result;
             if (stringResponse != _lastJson)
             {
                 MiningInfo = JsonConvert.DeserializeObject <MiningInfo>(stringResponse);
                 _lastJson  = stringResponse;
             }
         }
         catch (AggregateException ex)
         {
             if (ex.InnerExceptions.Count == 1 && ex.InnerException is TaskCanceledException)
             {
                 Logger.Warn("Timeout requesting current block status");
             }
             else if (ex.InnerException.GetType().Name == "WinHttpException")
             {
                 Logger.Warn("Error reading mining info:" + ex.InnerException.Message);
             }
             else if (ex.ToString().Contains("System.Net.Http.CurlException: Couldn't connect to server"))
             {
                 Logger.Warn("Could not connect to server to get new blocks");
             }
             else
             {
                 Logger.Error("Unexpected error reading blocks: " + ex.InnerException.Message);
             }
         }
         catch (Exception ex)
         {
             Logger.Error("Failed to update mining info", ex);
         }
         Thread.Sleep(1000);
     }
 }
예제 #6
0
        /// <summary>
        /// Free up our resources.
        /// </summary>
        public void Dispose()
        {
            // Log the dispose
            Logger.Debug("Stopping PlotChecker");

            // Instruct threads to termintae and wait for them to all die
            _isAlive = false;
            if (_threads != null)
            {
                foreach (Thread thread in _threads)
                {
                    thread.Join();
                }
                _threads = null;
            }
            Logger.Debug("PlotChecker threads all terminated");

            // Set values that should free up anything wanting to queue
            _maximumScoops = uint.MaxValue;
            _miningInfo    = null;
        }
예제 #7
0
 /// <summary>
 /// Create a new instance of this class.
 /// </summary>
 /// <param name="deadline">
 /// The deadline that has been found.
 /// </param>
 /// <param name="scoop">
 /// The scoop that this deadline was generated from.
 /// </param>
 /// <param name="miningInfo">
 /// The mining information that was used to generate this deadline.
 /// </param>
 public DeadlineFoundEventArgs(ulong deadline, Scoop scoop, MiningInfo miningInfo)
 {
     Scoop      = scoop;
     MiningInfo = miningInfo;
     Deadline   = deadline;
 }
예제 #8
0
        /// <summary>
        /// The main entry point for the threads that individually check for deadlines.
        /// </summary>
        private void ThreadEntry()
        {
            Shabal256 shabal = new Shabal256();

            byte[] hashBuffer = new byte[32 + Plot.SCOOP_SIZE];
            ulong  lastBlockHeightPrevGenCopied = 0;

            while (_isAlive)
            {
                // Get a few items from the queue to process
                Scoop[] scoops;
                lock (_scoopQueueLocker)
                {
                    scoops = new Scoop[_scoopQueue.Count > 100 ? 100 : _scoopQueue.Count];
                    if (scoops.Length > 0)
                    {
                        for (int i = 0; i < scoops.Length; i++)
                        {
                            scoops[i] = _scoopQueue[_scoopQueue.Count - i - 1];
                        }
                        _scoopQueue.RemoveRange(_scoopQueue.Count - scoops.Length, scoops.Length);
                    }
                }

                // If we didn't get an item or if for some reason the mining info has been wiped wait and try again
                if (scoops == null || scoops.Length < 1)
                {
                    Thread.Sleep(200);
                    continue;
                }

                foreach (Scoop scoop in scoops)
                {
                    // Breakout if we're no longer running
                    MiningInfo miningInfo = _miningInfo;
                    if (!_isAlive || miningInfo == null)
                    {
                        break;
                    }

                    // Ensure we're on right block
                    if (scoop.BlockHeight != miningInfo.BlockHeight)
                    {
                        continue;
                    }

                    // Calculate the deadline for this scoop
                    if (lastBlockHeightPrevGenCopied != miningInfo.BlockHeight)
                    {
                        Array.Copy(_miningInfo.PreviousGenerationSignatureBytes, hashBuffer, 32);
                        lastBlockHeightPrevGenCopied = miningInfo.BlockHeight;
                    }
                    Array.Copy(scoop.Data, 0, hashBuffer, 32, Plot.SCOOP_SIZE);
                    byte[] target       = shabal.ComputeBytes(hashBuffer).GetBytes();
                    ulong  targetResult = BitConverter.ToUInt64(target, 0);

                    // And with our target compute a deadline
                    ulong deadline = targetResult / miningInfo.BaseTarget;
                    if (deadline < miningInfo.Deadline)
                    {
                        DeadlineFound?.Invoke(this, new DeadlineFoundEventArgs(deadline, scoop, miningInfo));
                    }
                }
            }
        }
예제 #9
0
        /// <summary>
        /// This method is the main progress loop which is used to check how we're currently doing and update the UI accordingly.
        /// </summary>
        private void ProgressMonitoringThread()
        {
            bool       isFirstLoop        = true;
            byte       lastAnimationIndex = 0;
            MiningInfo miningInfo         = null;
            bool       lastVisible        = false;
            decimal    lastValue          = 0;

            while (_isAlive)
            {
                // Determine what state we should display - first if block has changed we need to reset everything back to begining
                if (miningInfo != _miningInfo)
                {
                    lastAnimationIndex = 0;
                    miningInfo         = _miningInfo;
                }
                bool visible = miningInfo != null;
                if (!visible)
                {
                    // Update UI if we've got a change
                    if (isFirstLoop || lastVisible != visible)
                    {
                        lastVisible = visible;
                        isFirstLoop = false;
                        lastValue   = 0;
                        ConsoleUi.ProgressBarHide();
                    }

                    // Wait to try again
                    Thread.Sleep(50);
                    continue;
                }

                // Determine how far through our readers are of this block (if we're in a block)
                decimal value          = 0m;
                string  text           = null;
                ulong   totalScoops    = (ulong)(UtilisedStorage * 1000000000 / Plot.SCOOPS_PER_PLOT / Plot.SCOOP_SIZE);
                ulong   readScoops     = 0;
                ulong   totalBytesRead = 0;
                foreach (PlotReader reader in _plotReaders)
                {
                    readScoops     += reader.ScoopsRead;
                    totalBytesRead += reader.BytesRead;
                }
                if (totalScoops > 0)
                {
                    value = (decimal)readScoops / (decimal)totalScoops;
                }

                // Now determine speed of reading
                double seconds    = DateTime.UtcNow.Subtract(_lastRoundStart).TotalSeconds;
                double bps        = totalBytesRead / seconds;
                double mbps       = Math.Round(bps / 1000 / 1000);
                string mbpsString = mbps.ToString();
                if (!mbpsString.Contains("."))
                {
                    mbpsString += ".0";
                }
                text = mbpsString + " MBps";

                // Based on this determine how much longer we have to go or how long it took depending on the data
                if (value < 1)
                {
                    double scoopsPerSecond = (double)readScoops / seconds;
                    if (scoopsPerSecond > 0)
                    {
                        ulong  remainingScoops  = totalScoops - readScoops;
                        double remainingSeconds = (double)remainingScoops / scoopsPerSecond;
                        if (remainingSeconds < 86400)
                        {
                            TimeSpan remaining     = TimeSpan.FromSeconds(remainingSeconds);
                            string   remainingText = remaining.Minutes.ToString();
                            if (remainingText.Length < 2)
                            {
                                remainingText = "0" + remainingText;
                            }
                            remainingText += ":";
                            if (remaining.Seconds < 10)
                            {
                                remainingText += "0";
                            }
                            remainingText += remaining.Seconds.ToString();
                            text          += "   ETA: " + remainingText;
                        }
                    }
                }
                else if (seconds > 0)
                {
                    text += "   Dur: " + TimeSpan.FromSeconds(seconds).ToString();
                }

                // Display this on first loop or a change in visibility
                if (lastVisible != visible || lastValue != value)
                {
                    ConsoleUi.ProgressBarSetup(lastAnimationIndex++, value, text);
                    if (lastAnimationIndex > 7)
                    {
                        lastAnimationIndex = 0;
                    }
                }
                lastValue   = value;
                lastVisible = true;
                isFirstLoop = false;

                // Wait to redraw
                Thread.Sleep(10);
            }
        }
예제 #10
0
 /// <summary>
 /// Reset the deadline submitter and remvoe any queued deadlines that are for old blocks.
 /// </summary>
 /// <param name="miningInfo">
 /// The current blocks mining information.
 /// </param>
 public void NotifyNewRound(MiningInfo miningInfo)
 {
     // Reset our deadlines list
     lock (_deadlineQueueLocker)
         _deadlineQueue.Clear();
 }