public void GenerateBlocks(WalletSecret walletSecret) { this.LastCoinStakeSearchInterval = 0; BlockTemplate pblocktemplate = null; bool tryToSync = true; while (true) { if (this.chain.Tip != this.consensusLoop.Tip) { return; } while (!this.connection.ConnectedNodes.Any() || this.chainState.IsInitialBlockDownload) { this.LastCoinStakeSearchInterval = 0; tryToSync = true; Task.Delay(TimeSpan.FromMilliseconds(this.minerSleep), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult(); } if (tryToSync) { tryToSync = false; if (this.connection.ConnectedNodes.Count() < 3 || this.chain.Tip.Header.Time < this.dateTimeProvider.GetTime() - 10 * 60) { //this.cancellationProvider.Cancellation.Token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(60000)); continue; } } if (pblocktemplate == null) { pblocktemplate = this.blockAssemblerFactory.Create(new AssemblerOptions() { IsProofOfStake = true }).CreateNewBlock(new Script()); } var pblock = pblocktemplate.Block; var pindexPrev = this.consensusLoop.Tip; var stakeTxes = new List <StakeTx>(); var spendable = this.wallet.GetSpendableTransactions(1); var coinset = this.coinView.FetchCoinsAsync(spendable.SelectMany(s => s.Transactions.Select(t => t.Id)).ToArray()).GetAwaiter().GetResult(); foreach (var unspentInfo in spendable) { foreach (var infoTransaction in unspentInfo.Transactions) { var set = coinset.UnspentOutputs.FirstOrDefault(f => f?.TransactionId == infoTransaction.Id); var utxo = set?._Outputs[infoTransaction.Index.Value]; if (utxo != null && utxo.Value > Money.Zero) { var stakeTx = new StakeTx(); stakeTx.TxOut = utxo; stakeTx.OutPoint = new OutPoint(set.TransactionId, infoTransaction.Index.Value); stakeTx.Address = unspentInfo.Address; stakeTx.OutputIndex = infoTransaction.Index.Value; stakeTx.HashBlock = this.chain.GetBlock((int)set.Height).HashBlock; stakeTx.UtxoSet = set; stakeTx.Secret = walletSecret; //temporary stakeTxes.Add(stakeTx); } } } // Trying to sign a block if (this.SignBlock(stakeTxes, pblock, pindexPrev, pblocktemplate.TotalFee)) { var blockResult = new BlockResult { Block = pblock }; this.CheckState(new ContextInformation(blockResult, this.network.Consensus), pindexPrev); pblocktemplate = null; } else { Task.Delay(TimeSpan.FromMilliseconds(this.minerSleep), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult(); } } }
/// <summary> /// Generates up to a specified number of blocks with a limited number of attempts. /// </summary> /// <param name="reserveScript"></param> /// <param name="generate">Number of blocks to generate. It is possible that less than the required number of blocks will be mined.</param> /// <param name="maxTries">Maximum number of attempts the miner will calculate PoW hash in order to find suitable ones to generate specified amount of blocks.</param> /// <returns>List with generated block's hashes</returns> public List <uint256> GenerateBlocks(ReserveScript reserveScript, ulong generate, ulong maxTries) { ulong nHeightStart = 0; ulong nHeightEnd = 0; ulong nHeight = 0; nHeightStart = (ulong)this.chain.Height; nHeight = nHeightStart; nHeightEnd = nHeightStart + generate; int nExtraNonce = 0; var blocks = new List <uint256>(); while (nHeight < nHeightEnd) { this.nodeLifetime.ApplicationStopping.ThrowIfCancellationRequested(); ChainedBlock chainTip = this.consensusLoop.Tip; if (this.chain.Tip != chainTip) { Task.Delay(TimeSpan.FromMinutes(1), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult(); continue; } BlockTemplate pblockTemplate = this.blockAssemblerFactory.Create(chainTip).CreateNewBlock(reserveScript.reserveSfullNodecript); if (Block.BlockSignature) { // 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. if (pblockTemplate.Block.Header.Time <= chainTip.Header.Time) { continue; } } this.IncrementExtraNonce(pblockTemplate.Block, chainTip, nExtraNonce); Block pblock = pblockTemplate.Block; while ((maxTries > 0) && (pblock.Header.Nonce < InnerLoopCount) && !pblock.CheckProofOfWork()) { this.nodeLifetime.ApplicationStopping.ThrowIfCancellationRequested(); ++pblock.Header.Nonce; --maxTries; } if (maxTries == 0) { break; } if (pblock.Header.Nonce == InnerLoopCount) { continue; } var newChain = new ChainedBlock(pblock.Header, pblock.GetHash(), chainTip); if (newChain.ChainWork <= chainTip.ChainWork) { continue; } var blockValidationContext = new BlockValidationContext { Block = pblock }; this.consensusLoop.AcceptBlockAsync(blockValidationContext).GetAwaiter().GetResult(); if (blockValidationContext.ChainedBlock == null) { this.logger.LogTrace("(-)[REORG-2]"); return(blocks); } if (blockValidationContext.Error != null) { if (blockValidationContext.Error == ConsensusErrors.InvalidPrevTip) { continue; } this.logger.LogTrace("(-)[ACCEPT_BLOCK_ERROR]"); return(blocks); } this.logger.LogInformation("Mined new {0} block: '{1}'.", BlockStake.IsProofOfStake(blockValidationContext.Block) ? "POS" : "POW", blockValidationContext.ChainedBlock); nHeight++; blocks.Add(pblock.GetHash()); pblockTemplate = null; } return(blocks); }
public List <uint256> GenerateBlocks(ReserveScript reserveScript, ulong generate, ulong maxTries) { ulong nHeightStart = 0; ulong nHeightEnd = 0; ulong nHeight = 0; nHeightStart = (ulong)this.chain.Height; nHeight = nHeightStart; nHeightEnd = nHeightStart + generate; int nExtraNonce = 0; var blocks = new List <uint256>(); while (nHeight < nHeightEnd) { this.nodeLifetime.ApplicationStopping.ThrowIfCancellationRequested(); try { ChainedBlock chainTip = this.consensusLoop.Tip; if (this.chain.Tip != chainTip) { Task.Delay(TimeSpan.FromMinutes(1), this.nodeLifetime.ApplicationStopping).GetAwaiter().GetResult(); continue; } BlockTemplate pblockTemplate = this.blockAssemblerFactory.Create(chainTip).CreateNewBlock(reserveScript.reserveSfullNodecript); if (Block.BlockSignature) { // POS: make sure the POS consensus rules are valid if (pblockTemplate.Block.Header.Time <= chainTip.Header.Time) { continue; } } this.IncrementExtraNonce(pblockTemplate.Block, chainTip, nExtraNonce); Block pblock = pblockTemplate.Block; while ((maxTries > 0) && (pblock.Header.Nonce < InnerLoopCount) && !pblock.CheckProofOfWork()) { this.nodeLifetime.ApplicationStopping.ThrowIfCancellationRequested(); ++pblock.Header.Nonce; --maxTries; } if (maxTries == 0) { break; } if (pblock.Header.Nonce == InnerLoopCount) { continue; } var newChain = new ChainedBlock(pblock.Header, pblock.GetHash(), chainTip); if (newChain.ChainWork <= chainTip.ChainWork) { continue; } this.chain.SetTip(newChain); var blockResult = new BlockResult { Block = pblock }; this.consensusLoop.AcceptBlock(new ContextInformation(blockResult, this.network.Consensus)); this.consensusLoop.Puller.SetLocation(newChain); if (blockResult.ChainedBlock == null) { break; // Reorg. } if (blockResult.Error != null) { return(blocks); } // Push the block to disk, so it is available when peers ask for it. this.blockRepository.PutAsync(blockResult.ChainedBlock.HashBlock, new List <Block> { pblock }).GetAwaiter().GetResult(); // Similar logic to what's in the full node code. this.chainState.HighestValidatedPoW = this.consensusLoop.Tip; this.signals.SignalBlock(pblock); this.logger.LogInformation("Mined new {0} block: '{1}'.", BlockStake.IsProofOfStake(blockResult.Block) ? "POS" : "POW", blockResult.ChainedBlock); nHeight++; blocks.Add(pblock.GetHash()); pblockTemplate = null; } catch (ConsensusErrorException cer) { if (cer.ConsensusError == ConsensusErrors.InvalidPrevTip) { continue; } throw; } } return(blocks); }