Пример #1
0
        /// <summary>
        /// Executes until the required work (difficulty) has been reached. This is the "mining" process.
        /// </summary>
        /// <param name="context">The <see cref="MineBlockContext"/>.</param>
        /// <returns><c>True</c> if the block was successfully mined or <c>false</c> otherwise.</returns>
        private bool MineBlock(MineBlockContext context)
        {
            if (this.network.Consensus.LastPOWBlock != 0 && context.ChainTip.Height > this.network.Consensus.LastPOWBlock)
            {
                context.BlockTemplate.Block.Header.Nonce = InnerLoopCount;
                return(false);
            }

            context.ExtraNonce = this.IncrementExtraNonce(context.BlockTemplate.Block, context.ChainTip, context.ExtraNonce);

            Block block = context.BlockTemplate.Block;

            while ((context.MaxTries > 0) && (block.Header.Nonce < InnerLoopCount) && !block.CheckProofOfWork())
            {
                this.miningCancellationTokenSource.Token.ThrowIfCancellationRequested();

                ++block.Header.Nonce;
                --context.MaxTries;
            }

            if (context.MaxTries == 0)
            {
                return(false);
            }

            return(true);
        }
Пример #2
0
        /// <summary>
        ///     Ensures that the node is synced before mining is allowed to start.
        /// </summary>
        bool ConsensusIsAtTip(MineBlockContext context)
        {
            this.miningCancellationTokenSource.Token.ThrowIfCancellationRequested();

            if (context.ChainTip != this.consensusManager.Tip)
            {
                context.ChainTip      = this.consensusManager.Tip;
                context.BlockTemplate = null;
            }

            // Genesis on a regtest network is a special case. We need to regard ourselves as outside of IBD to
            // bootstrap the mining.
            if (context.ChainTip.Height == 0)
            {
                return(true);
            }

            if (this.initialBlockDownloadState.IsInitialBlockDownload())
            {
                Task.Delay(TimeSpan.FromMinutes(1), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult();
                return(false);
            }

            return(true);
        }
Пример #3
0
        private void OnBlockMined(MineBlockContext context)
        {
            this.logger.LogInformation("Mined new {0} block: '{1}'.", BlockStake.IsProofOfStake(context.ChainedHeaderBlock.Block) ? "POS" : "POW", context.ChainedHeaderBlock.ChainedHeader);

            context.CurrentHeight++;

            context.Blocks.Add(context.BlockTemplate.Block.GetHash());
            context.BlockTemplate = null;
        }
 private bool CheckValidationContextPreviousTip(MineBlockContext context)
 {
     if (context.ValidationContext.Error != null)
     {
         if (context.ValidationContext.Error == ConsensusErrors.InvalidPrevTip)
         {
             return(false);
         }
     }
     return(true);
 }
Пример #5
0
 bool MineBlock(MineBlockContext context)
 {
     if (minerSettings.UseOpenCL && openCLMiner.CanMine())
     {
         return(MineBlockOpenCL(context));
     }
     else
     {
         return(MineBlockCpu(context));
     }
 }
        /// <summary>
        /// Ensures that the node is synced before mining is allowed to start.
        /// </summary>
        private bool ConsensusIsAtTip(MineBlockContext context)
        {
            this.miningCancellationTokenSource.Token.ThrowIfCancellationRequested();

            context.ChainTip = this.consensusManager.Tip;
            if (this.chain.Tip != context.ChainTip)
            {
                Task.Delay(TimeSpan.FromMinutes(1), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult();
                return(false);
            }

            return(true);
        }
Пример #7
0
        /// <summary>
        /// Creates a proof of work or proof of stake block depending on the network the node is running on.
        /// <para>
        /// If the node is on a POS network, make sure the POS consensus rules are valid. This is required for
        /// generation of blocks inside tests, where it is possible to generate multiple blocks within one second.
        /// </para>
        /// </summary>
        private bool BuildBlock(MineBlockContext context)
        {
            context.BlockTemplate = this.blockProvider.BuildPowBlock(context.ChainTip, context.ReserveScript.ReserveFullNodeScript);

            if (this.network.Consensus.IsProofOfStake)
            {
                if (context.BlockTemplate.Block.Header.Time <= context.ChainTip.Header.Time)
                {
                    return(false);
                }
            }

            return(true);
        }
Пример #8
0
        private bool MineBlock(MineBlockContext context)
        {
            if (this.network.NetworkType == NetworkType.Regtest)
            {
                return(MineBlockRegTest(context));
            }

            if (this.minerSettings.UseOpenCL && this.openCLMiner.CanMine())
            {
                return(MineBlockOpenCL(context));
            }

            return(MineBlockCpu(context));
        }
Пример #9
0
        /// <summary>
        /// Validate the mined block by passing it to the consensus rule engine.
        /// <para>
        /// On successful block validation the block will be connected to the chain.
        /// </para>
        /// </summary>
        private bool ValidateAndConnectBlock(MineBlockContext context)
        {
            ChainedHeader chainedHeader = this.consensusManager.BlockMinedAsync(context.BlockTemplate.Block).GetAwaiter().GetResult();

            if (chainedHeader == null)
            {
                this.logger.LogTrace("(-)[BLOCK_VALIDATION_ERROR]:false");
                return(false);
            }

            context.ChainedHeaderBlock = new ChainedHeaderBlock(context.BlockTemplate.Block, chainedHeader);

            return(true);
        }
Пример #10
0
        /// <summary>
        ///     Ensures that the block was properly mined by checking the block's work against the next difficulty target.
        /// </summary>
        bool ValidateMinedBlock(MineBlockContext context)
        {
            var chainedHeader = new ChainedHeader(context.BlockTemplate.Block.Header,
                                                  context.BlockTemplate.Block.GetHash(), context.ChainTip);

            if (chainedHeader.ChainWork <= context.ChainTip.ChainWork)
            {
                return(false);
            }

            var block = context.BlockTemplate.Block;

            return(true);
        }
Пример #11
0
        /// <summary>
        /// Ensures that the block was properly mined by checking the block's work against the next difficulty target.
        /// </summary>
        private bool ValidateMinedBlock(MineBlockContext context)
        {
            if (context.BlockTemplate.Block.Header.Nonce == InnerLoopCount)
            {
                return(false);
            }

            var chainedHeader = new ChainedHeader(context.BlockTemplate.Block.Header, context.BlockTemplate.Block.GetHash(), context.ChainTip);

            if (chainedHeader.ChainWork <= context.ChainTip.ChainWork)
            {
                return(false);
            }

            return(true);
        }
Пример #12
0
        private bool IsProofOfWorkAllowed(MineBlockContext context)
        {
            var newBlockHeight = context.ChainTip.Height + 1;

            if (this.network.Consensus.Options is X1ConsensusOptions options)
            {
                if (options.IsAlgorithmAllowed(false, newBlockHeight))
                {
                    return(true);
                }

                Task.Delay(1000).Wait(); // pause the miner
                return(false);
            }

            return(true);
        }
Пример #13
0
        /// <inheritdoc/>
        public List <uint256> GenerateBlocks(ReserveScript reserveScript, ulong amountOfBlocksToMine, ulong maxTries)
        {
            var context = new MineBlockContext(amountOfBlocksToMine, (ulong)this.chainIndexer.Height, maxTries, reserveScript);

            while (context.MiningCanContinue)
            {
                if (!this.ConsensusIsAtTip(context))
                {
                    continue;
                }

                if (!this.BuildBlock(context))
                {
                    continue;
                }

                if (!this.IsProofOfWorkAllowed(context))
                {
                    continue;
                }

                if (!this.MineBlock(context))
                {
                    break;
                }

                if (!this.ValidateMinedBlock(context))
                {
                    continue;
                }

                if (!this.ValidateAndConnectBlock(context))
                {
                    continue;
                }

                this.OnBlockMined(context);
            }

            return(context.Blocks);
        }
        /// <summary>
        /// Validate the mined block by passing it to the consensus rule engine.
        /// <para>
        /// On successfull block validation the block will be connected to the chain.
        /// </para>
        /// </summary>
        private bool ValidateAndConnectBlock(MineBlockContext context)
        {
            context.ValidationContext = new ValidationContext {
                Block = context.BlockTemplate.Block
            };
            this.consensusLoop.AcceptBlockAsync(context.ValidationContext).GetAwaiter().GetResult();

            if (context.ValidationContext.ChainedHeader == null)
            {
                this.logger.LogTrace("(-)[REORG-2]");
                return(false);
            }

            if (context.ValidationContext.Error != null && context.ValidationContext.Error != ConsensusErrors.InvalidPrevTip)
            {
                this.logger.LogTrace("(-)[ACCEPT_BLOCK_ERROR]");
                return(false);
            }

            return(true);
        }
Пример #15
0
        /// <summary>
        ///     Executes until the required work (difficulty) has been reached. This is the "mining" process.
        /// </summary>
        bool MineBlock(MineBlockContext context)
        {
            context.ExtraNonce = IncrementExtraNonce(context.BlockTemplate.Block, context.ChainTip, context.ExtraNonce);

            var block = context.BlockTemplate.Block;

            while (context.MaxTries > 0 && block.Header.Nonce < InnerLoopCount && !block.CheckProofOfWork())
            {
                this.miningCancellationTokenSource.Token.ThrowIfCancellationRequested();

                ++block.Header.Nonce;
                --context.MaxTries;
            }

            if (context.MaxTries == 0)
            {
                return(false);
            }

            return(true);
        }
Пример #16
0
        bool MineBlockOpenCL(MineBlockContext context)
        {
            var block = context.BlockTemplate.Block;

            block.Header.Nonce = 0;
            context.ExtraNonce = this.IncrementExtraNonce(block, context.ChainTip, context.ExtraNonce);

            var iterations = uint.MaxValue / (uint)this.minerSettings.OpenCLWorksizeSplit;
            var nonceStart = ((uint)context.ExtraNonce - 1) * iterations;

            var stopwatch = new Stopwatch();

            stopwatch.Start();

            var headerBytes = block.Header.ToBytes(this.network.Consensus.ConsensusFactory);
            var bits        = block.Header.Bits.ToUInt256();
            var foundNonce  = this.openCLMiner.FindPow(headerBytes, bits.ToBytes(), nonceStart, iterations);

            stopwatch.Stop();

            if (foundNonce > 0)
            {
                block.Header.Nonce = foundNonce;
                if (block.Header.CheckProofOfWork())
                {
                    return(true);
                }
            }

            this.LogMiningInformation(context.ExtraNonce, iterations, stopwatch.Elapsed.TotalSeconds, block.Header.Bits.Difficulty, $"{this.openCLMiner.GetDeviceName()}");

            if (context.ExtraNonce >= this.minerSettings.OpenCLWorksizeSplit)
            {
                block.Header.Time += 1;
                context.ExtraNonce = 0;
            }

            return(false);
        }
Пример #17
0
        /// <summary>
        ///     Executes until the required work (difficulty) has been reached. This is the "mining" process.
        /// </summary>
        bool MineBlockCpu(MineBlockContext context)
        {
            context.ExtraNonce = IncrementExtraNonce(context.BlockTemplate.Block, context.ChainTip, context.ExtraNonce);

            var block = context.BlockTemplate.Block;

            block.Header.Nonce = 0;

            uint looplength  = 2_000_000;
            int  threads     = this.minerSettings.MineThreadCount; // Environment.ProcessorCount;
            int  batch       = threads;
            var  totalNonce  = batch * looplength;
            uint winnernonce = 0;
            bool found       = false;

            ParallelOptions options = new ParallelOptions()
            {
                MaxDegreeOfParallelism = threads, CancellationToken = this.miningCancellationTokenSource.Token
            };

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            int fromInclusive = context.ExtraNonce * batch;
            int toExclusive   = fromInclusive + batch;

            Parallel.For(fromInclusive, toExclusive, options, (index, state) =>
            {
                if (this.miningCancellationTokenSource.Token.IsCancellationRequested)
                {
                    return;
                }

                uint256 bits = block.Header.Bits.ToUInt256();

                var headerbytes = block.Header.ToBytes(this.network.Consensus.ConsensusFactory);
                uint nonce      = (uint)index * looplength;

                var end = nonce + looplength;

                //this.logger.LogDebug($"nonce={nonce}, end={end}, index={index}, context.ExtraNonce={context.ExtraNonce}, looplength={looplength}");

                while (nonce < end)
                {
                    if (CheckProofOfWork(headerbytes, nonce, bits))
                    {
                        winnernonce = nonce;
                        found       = true;
                        state.Stop();

                        return;
                    }

                    if (state.IsStopped)
                    {
                        return;
                    }

                    ++nonce;
                }
            });

            stopwatch.Stop();

            if (found)
            {
                block.Header.Nonce = winnernonce;
                if (block.Header.CheckProofOfWork())
                {
                    return(true);
                }
            }

            this.LogMiningInformation(context.ExtraNonce, totalNonce, stopwatch.Elapsed.TotalSeconds, block.Header.Bits.Difficulty, $"{threads} threads");

            return(false);
        }
Пример #18
0
        /// <summary>
        ///     Executes until the required work (difficulty) has been reached. This is the "mining" process.
        /// </summary>
        bool MineBlock(MineBlockContext context)
        {
            context.ExtraNonce = IncrementExtraNonce(context.BlockTemplate.Block, context.ChainTip, context.ExtraNonce);

            var block = context.BlockTemplate.Block;

            block.Header.Nonce = 0;

            uint looplength  = 2_000_000;
            int  threads     = this.minerSettings.MineThreadCount; // Environment.ProcessorCount;
            int  batch       = threads;
            var  totalNonce  = batch * looplength;
            uint winnernonce = 0;
            bool found       = false;

            ParallelOptions options = new ParallelOptions()
            {
                MaxDegreeOfParallelism = threads, CancellationToken = this.miningCancellationTokenSource.Token
            };

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            int fromInclusive = context.ExtraNonce * batch;
            int toExclusive   = fromInclusive + batch;

            Parallel.For(fromInclusive, toExclusive, options, (index, state) =>
            {
                if (this.miningCancellationTokenSource.Token.IsCancellationRequested)
                {
                    return;
                }

                uint256 bits = block.Header.Bits.ToUInt256();

                var headerbytes = block.Header.ToBytes(this.network.Consensus.ConsensusFactory);
                uint nonce      = (uint)index * looplength;

                var end = nonce + looplength;

                //this.logger.LogDebug($"nonce={nonce}, end={end}, index={index}, context.ExtraNonce={context.ExtraNonce}, looplength={looplength}");

                while (nonce < end)
                {
                    if (CheckProofOfWork(headerbytes, nonce, bits))
                    {
                        winnernonce = nonce;
                        found       = true;
                        state.Stop();

                        return;
                    }

                    if (state.IsStopped)
                    {
                        return;
                    }

                    ++nonce;
                }
            });

            stopwatch.Stop();

            if (found)
            {
                block.Header.Nonce = winnernonce;
                if (block.Header.CheckProofOfWork())
                {
                    return(true);
                }
            }

            var MHashedPerSec = Math.Round((totalNonce / stopwatch.Elapsed.TotalSeconds) / 1_000_000, 4);

            var currentDifficulty  = BigInteger.ValueOf((long)block.Header.Bits.Difficulty);
            var MHashedPerSecTotal = (double)currentDifficulty.Multiply(Target.Pow256).Divide(Target.Difficulty1.ToBigInteger()).Divide(BigInteger.ValueOf(10 * 60)).LongValue / 1_000_000.0;

            this.logger.LogInformation($"Difficulty={block.Header.Bits.Difficulty}, extraNonce={context.ExtraNonce}, hashes={totalNonce}, execution={stopwatch.Elapsed.TotalSeconds} sec, hash-rate={MHashedPerSec} MHash/sec ({threads} threads), network hash-rate ~{MHashedPerSecTotal} MHash/sec");

            return(false);
        }