/// <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); }
/// <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); }
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); }
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); }
/// <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); }
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)); }
/// <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); }
/// <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); }
/// <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); }
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); }
/// <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); }
/// <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); }
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); }
/// <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); }
/// <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); }